Просмотр файла Cool JS v2.6/jcool-2.6.js

Размер файла: 37.89Kb
  1. /*!
  2. * CoolJS JavaScript Library v2.6
  3. * https://coolcms.ru/
  4. * https://vk.com/fastgrid
  5. *
  6. * Copyright Dmitry Kokorin
  7. * Released under the MIT license
  8. * https://coolcms.ru/license/
  9. *
  10. * Documentation: https://coolcms.ru/docs/5-cool_js
  11. * Date: 2018-01-20T17:24Z
  12. */
  13.  
  14. (function (w, d) {
  15. 'use strict';
  16. if (!d.querySelectorAll) {
  17. alert('Ваш браузер устарел,пожалуйста,обновите браузер чтобы продолжить работу с сайтом');
  18. return;
  19. }
  20.  
  21. /*
  22. префиксы для браузеров
  23.  
  24. element.style[getPrefix(property)]
  25. @property - HTMLElement property
  26. */
  27. function getPrefix(a){
  28. const prefixes = ['Moz', 'Webkit', 'Ms'], div = d.createElement('div');
  29. let c = a.split('-'),f = '';
  30. if (c.length > 0) for (let i = 0; i < c.length; ++i) f += c[i].substring(0, 1).toUpperCase() + c[i].substring(1).toLowerCase();
  31. for(let i=0; i<prefixes.length; ++i){
  32. let s = prefixes[i] + f, m = prefixes[i] + f.substring(0, 1).toLowerCase() + f.substring(1);
  33. if (typeof div.style[m] != 'undefined') {
  34. div.remove();
  35. return m;
  36. } else if (typeof div.style[s] != 'undefined') {
  37. div.remove();
  38. return s;
  39. }
  40. }
  41. return f.substring(0, 1).toLowerCase() + f.substring(1);
  42. }
  43.  
  44. /*
  45. вспомогательная ф-ция для метода fadeIn
  46.  
  47. getFadeIn(element)
  48. @element - HTMLElement
  49. */
  50. function getFadeIn(a) {
  51. let s = a.style,
  52. ani;
  53. if (s.display == 'block' && s[getPrefix('opacity')] === 1) return;
  54. s[getPrefix('opacity')] = 0;
  55. s.display = 'block';
  56. ani = requestAnimationFrame(animate);
  57.  
  58. function animate() {
  59. if (s[getPrefix('opacity')] > 1) {
  60. s[getPrefix('opacity')] = 1;
  61. cancelAnimationFrame(ani);
  62. } else {
  63. s[getPrefix('opacity')] = +s[getPrefix('opacity')] + 0.1;
  64. cancelAnimationFrame(ani);
  65. ani = requestAnimationFrame(animate);
  66. }
  67. }
  68. return true;
  69. }
  70.  
  71. /*
  72. вспомогательная ф-ция для метода fadeOut
  73.  
  74. getFadeOut(element)
  75. @element - HTMLElement
  76. */
  77. function getFadeOut(a) {
  78. let s = a.style,
  79. ani;
  80. if (s.display == 'none' || s[getPrefix('opacity')] === 0) return;
  81. ani = requestAnimationFrame(animate);
  82.  
  83. function animate() {
  84. if (s[getPrefix('opacity')] < 0) {
  85. s.display = 'none';
  86. s[getPrefix('opacity')] = 0;
  87. cancelAnimationFrame(ani);
  88. } else {
  89. s[getPrefix('opacity')] = +s[getPrefix('opacity')] - 0.1;
  90. cancelAnimationFrame(ani);
  91. ani = requestAnimationFrame(animate);
  92. }
  93. }
  94. return true;
  95. }
  96.  
  97. /*
  98. вспомогательная ф-ция для метода scrollTo
  99.  
  100. scroll to element - scrolling.scrollTo(element, duration)
  101. @element - HTMLElement
  102. @duration - integer ms
  103.  
  104. scroll to position - scrolling.animateScroll(position, duration)
  105. @position - integer px
  106. @duration - integer ms
  107. */
  108. let scrolling = {
  109. scrollTo: function (anchor, duration) {
  110. let scroll = 0;
  111. do {
  112. scroll += anchor.offsetTop;
  113. anchor = anchor.offsetParent;
  114. } while (anchor);
  115. scroll = scroll >= 0 ? scroll : 1;
  116. if (w.event.preventDefault) w.event.preventDefault();
  117. w.event.returnValue = false;
  118. duration = duration || null;
  119. this.animateScroll(scroll, duration);
  120. return false;
  121. },
  122. animateScroll: function (pos, duration) {
  123. d.documentElement.scrollTop = w.scrollY + 1;
  124. let element = (d.documentElement && d.documentElement.scrollTop) ? d.documentElement : d.body,
  125. start = element.scrollTop,
  126. change = pos - start,
  127. currentTime = 0,
  128. increment = 20;
  129. duration = duration || 1000;
  130. let animateScroll = function () {
  131. currentTime += increment;
  132. let val = Math.easeInOutQuad(currentTime, start, change, duration);
  133. element.scrollTop = val;
  134. if (currentTime < duration) setTimeout(animateScroll, increment);
  135. };
  136. animateScroll();
  137. }
  138. };
  139. Math.easeInOutQuad = (t, b, c, d) => {
  140. t /= d / 2;
  141. if (t < 1) return c / 2 * t * t + b;
  142. t--;
  143. return -c / 2 * (t * (t - 2) - 1) + b;
  144. };
  145.  
  146. /* основной класс */
  147. class App {
  148.  
  149. /*
  150. Конструктор класса
  151.  
  152. @a - string or HTMLCollection
  153. */
  154. constructor(a) {
  155. this.string = a || null;
  156. this.isString = typeof this.string == 'string';
  157. this.isObject = this.string == 'object';
  158. if(this.isString && /<[a-z]+><\/[a-z]+>/.test(a)){
  159. let z=a.match(/[a-z]+/);
  160. if (z.length < 1) return;
  161. this.element = d.createElement(z[0]);
  162. }else{
  163. this.element = this.isString ? (a.charAt(0) == '[' ? d.getElementsByName(a.substr(1).slice(0, -1)) : d.querySelectorAll(this.string)) : (this.string || null);
  164. }
  165. }
  166.  
  167. /*
  168. Добавляет класс элементам
  169.  
  170. @a - string class name
  171. */
  172. addClass(a) {
  173. if (this.isString || this.isObject) {
  174. for (let i = 0; i < this.element.length; ++i) this.element[i].classList.add(a);
  175. } else {
  176. this.element.classList.add(a);
  177. }
  178. return this;
  179. }
  180.  
  181. /*
  182. Вставляет HTMLElement или HTMLCollection в конец элементов
  183.  
  184. @a - HTMLElement
  185. */
  186. after(a){
  187. if (this.isString) {
  188. for (let i = 0; i < this.element.length; ++i) this.element[i].appendChild(a);
  189. } else {
  190. this.element.appendChild(a);
  191. }
  192. return this;
  193. }
  194.  
  195. /*
  196. Вставляет произвольный текст или html-код в конец элементов
  197.  
  198. @a - textContent
  199. */
  200. append(a) {
  201. if (this.isString) {
  202. for (let i = 0; i < this.element.length; ++i) this.element[i].innerHTML = this.element[i].innerHTML + a;
  203. } else {
  204. this.element.innerHTML = this.element.innerHTML + a;
  205. }
  206. return this;
  207. }
  208.  
  209. /*
  210. Получает или устанавливает атрибуты элементов
  211.  
  212. @a - property
  213. @b - value
  214. */
  215. attr(a, b) {
  216. b = b || null;
  217. if (this.isString || this.isObject) {
  218. if (b) {
  219. for (let i = 0; i < this.element.length; ++i) this.element[i].setAttribute(a, b);
  220. return this;
  221. }
  222. return this.element[0].getAttribute(a);
  223. } else {
  224. return b ? (this.element.setAttribute(a, b), this) : this.element.getAttribute(a);
  225. }
  226. }
  227.  
  228. /*
  229. Вставляет HTMLElement или HTMLCollection в начало элементов
  230.  
  231. @a - HTMLElement
  232. */
  233. before(a){
  234. if (this.isString) {
  235. for (let i = 0; i < this.element.length; ++i) this.element[i].insertBefore(a,this.element[i].firstChild);
  236. } else {
  237. this.element.insertBefore(a,this.element.firstChild);
  238. }
  239. return this;
  240. }
  241.  
  242. /*
  243. Убирает фокус с элемента
  244. */
  245. blur() {
  246. if (this.isString || this.isObject) {
  247. for (let i = 0; i < this.element.length; ++i) this.element[i].blur();
  248. } else {
  249. this.element.blur();
  250. }
  251. return this;
  252. }
  253.  
  254. /*
  255. Меняет старый класс на новый у элементов
  256.  
  257. @a - old className
  258. @b - new className
  259. */
  260. changeClass(a, b) {
  261. if (this.isString || this.isObject) {
  262. for (let i = 0; i < this.element.length; ++i) {
  263. this.element[i].classList.remove(a);
  264. this.element[i].classList.add(b);
  265. }
  266. } else {
  267. this.element.classList.remove(a);
  268. this.element.classList.add(b);
  269. }
  270. return this;
  271. }
  272.  
  273. /*
  274. Проверяет, отмечен ли чекбокс или радио-кнопка
  275. */
  276. checked() {
  277. return (this.isString || this.isObject) ? (this.element[0].getAttribute('checked') == 'checked' ? true : false) : (this.element.getAttribute('checked') == 'checked' ? true : false);
  278. }
  279.  
  280. /*
  281. Собирает дочерние элементы
  282.  
  283. @a - string selector
  284. если параметр @a указан, будут найдены элементы с указанным селектором
  285. */
  286. child(a) {
  287. let b = [];
  288. if(this.isString || this.isObject){
  289. for (let i = 0; i < this.element.length; ++i){
  290. let c = a ? this.element[i].querySelectorAll(a) : this.element[i].children;
  291. for(let j = 0; j < c.length; ++j) b.push(c[i]);
  292. }
  293. }else{
  294. let c = a ? this.element.querySelectorAll(a) : this.element.children;
  295. for(let j = 0; j < c.length; ++j) b.push(c[i]);
  296. }
  297. this.element = b;
  298. return this;
  299. }
  300.  
  301. /*
  302. Устанавливает css свойства
  303.  
  304. @a - object {property: value, ...}
  305. */
  306. css(a) {
  307. a = a || {};
  308. for (let b in a) {
  309. if (this.isString || this.isObject) {
  310. for (let i = 0; i < this.element.length; ++i) this.element[i].style[getPrefix(b)] = a[b];
  311. } else {
  312. this.element.style[getPrefix(b)] = a[b];
  313. }
  314. }
  315. return this;
  316. }
  317.  
  318. /*
  319. Получает значение data-атрибута
  320.  
  321. @a - data-prop
  322. */
  323. data(a) {
  324. return this.isString ? this.element[0].getAttribute('data-' + a) : this.element.getAttribute('data-' + a);
  325. }
  326.  
  327. /*
  328. Перебирает массив
  329.  
  330. @a - array
  331. */
  332. each(a) {
  333. for (let i = 0; i < this.element.length; ++i) a.apply(this.element[i], arguments);
  334. return this;
  335. }
  336.  
  337. /*
  338. Очищает содержимое элементов
  339. */
  340. empty() {
  341. if (this.isString) {
  342. for (let i = 0; i < this.element.length; ++i) this.element[i].innerHTML = '';
  343. } else {
  344. this.element.innerHTML = '';
  345. }
  346. return this;
  347. }
  348.  
  349. /*
  350. Плавно показывает скрытые элементы
  351. */
  352. fadeIn() {
  353. if (this.isString || this.isObject) {
  354. for (let i = 0; i < this.element.length; ++i) getFadeIn(this.element[i]);
  355. } else {
  356. getFadeIn(this.element);
  357. }
  358. return this;
  359. }
  360.  
  361. /*
  362. Плавно скрывает элементы
  363. */
  364. fadeOut() {
  365. if (this.isString || this.isObject) {
  366. for (let i = 0; i < this.element.length; ++i) getFadeOut(this.element[i]);
  367. } else {
  368. getFadeOut(this.element);
  369. }
  370. return this;
  371. }
  372.  
  373. /*
  374. Перебирает HTMLInputElement типа file и возвращает массив найденных файлов
  375. */
  376. files() {
  377. let a = [];
  378. if (this.isString || this.isObject) {
  379. for (let i = 0; i < this.element.length; ++i)
  380. for (let j = 0; j < this.element[i].files.length; ++j) a.push(this.element[i].files[j]);
  381. return a;
  382. } else {
  383. for (let i = 0; i < this.element.files; ++i) a.push(this.element.files[i]);
  384. return a;
  385. }
  386. }
  387.  
  388. /*
  389. Устанавливает фокус на первый элемент
  390. */
  391. focus() {
  392. if (this.isString || this.isObject) {
  393. this.element[0].focus();
  394. } else {
  395. this.element.focus();
  396. }
  397. return this;
  398. }
  399.  
  400. /*
  401. Проверяет наличие класса у элементов
  402.  
  403. @a - string className
  404. @b - int index
  405. */
  406. hasClass(a, b) {
  407. b = b || 0;
  408. return (this.isString || this.isObject) ? this.element[b].classList.contains(a) : this.element.classList.contains(a);
  409. }
  410.  
  411. /*
  412. Получает или устанавливает высоту элементов
  413.  
  414. @a - int value px
  415. @b - int index
  416.  
  417. для window и document высоту можно только получить
  418. */
  419. height(a, b) {
  420. a = typeof a != 'undefined' ? a : null;
  421. b = b || 0;
  422. if(this.string==w){
  423. return w.innerHeight;
  424. }else if(this.string==d){
  425. return d.innerHeight;
  426. }else if(this.isString || this.isObject){
  427. if(a){
  428. for(let i=0;i<this.element.length;++i) this.element[i].style.height=a;
  429. return this;
  430. }else{
  431. return this.element[b].scrollHeight;
  432. }
  433. }else{
  434. return a?(this.element.style.height=a,this):this.element.scrollHeight;
  435. }
  436. }
  437.  
  438. /*
  439. Скрывает элементы
  440. */
  441. hide() {
  442. if (this.isString || this.isObject) {
  443. for (let i = 0; i < this.element.length; ++i) this.element[i].style.display = 'none';
  444. } else {
  445. this.element.style.display = 'none';
  446. }
  447. return this;
  448. }
  449.  
  450. /*
  451. Получает или устанавливает html-код элемента или произвольный текст
  452.  
  453. @a - textContent or function
  454. @b - int index
  455. */
  456. html(a, b) {
  457. a = typeof a != 'undefined' ? a : null;
  458. b = b || 0;
  459. if (this.isString || this.isObject) {
  460. if (a) {
  461. for (let i = 0; i < this.element.length; ++i) this.element[i].innerHTML = typeof a == 'function' ? a() : a;
  462. return this;
  463. } else {
  464. return this.element[b].innerHTML;
  465. }
  466. } else {
  467. if (a) {
  468. this.element.innerHTML = typeof a == 'function' ? a() : a;
  469. return this;
  470. } else {
  471. return this.element.innerHTML;
  472. }
  473. }
  474. }
  475.  
  476. /*
  477. Вставляет HTMLElement в начало элемента
  478.  
  479. @a - HTMLElement
  480. */
  481. insertBefore(a){
  482. if (this.isString) {
  483. for (let i = 0; i < this.element.length; ++i) this.element[i].parentNode.insertBefore(a,firstChild);
  484. } else {
  485. this.element.parentNode.insertBefore(a,firstChild);
  486. }
  487. return this;
  488. }
  489.  
  490. /*
  491. Вставляет HTMLElement в конец элемента
  492.  
  493. @a - HTMLElement
  494. */
  495. insertAfter(a){
  496. if (this.isString) {
  497. for (let i = 0; i < this.element.length; ++i) this.element[i].parentNode.appendChild(a);
  498. } else {
  499. this.element.parentNode.appendChild(a);
  500. }
  501. return this;
  502. }
  503.  
  504. /*
  505. Собирает следующие элементы
  506.  
  507. @a - string className
  508. если параметр @a указан будут найдены элементы с заданным селектором
  509. */
  510. next() {
  511. let b = [];
  512. if (this.isString || this.isObject) {
  513. for (let i = 0; i < this.element.length; ++i){
  514. if(a){
  515. let c = this.element[i].parentNode.querySelectorAll(a);
  516. for(let j = 0; j < c.length; ++j) if(c[j] == this.element[i].nextElementSibling) b.push(this.element[i].nextElementSibling);
  517. }else{
  518. b.push(this.element[i].nextElementSibling);
  519. }
  520. }
  521. } else {
  522. if(a){
  523. let c = this.element.parentNode.querySelectorAll(a);
  524. for(let j = 0; j < c.length; ++j) if(c[j] == this.element.nextElementSibling) b.push(this.element.nextElementSibling);
  525. }else{
  526. b.push(this.element.nextElementSibling);
  527. }
  528. }
  529. this.element = b;
  530. return this;
  531. }
  532.  
  533. /*
  534. Отключает обработчик событий
  535.  
  536. @a - event
  537. @b - callback function
  538. */
  539. off(a, b) {
  540. b = typeof b == 'function' ? b : null;
  541. if (this.isString || this.isObject) {
  542. let i = 0,
  543. j = this,
  544. t = w.setInterval(() => {
  545. if (i < j.element.length) {
  546. j.element[i].removeEventListener(a, b);
  547. ++i;
  548. } else {
  549. w.clearInterval(t);
  550. }
  551. }, 20);
  552. } else {
  553. this.element.removeEventListener(a, b);
  554. }
  555. return this;
  556. }
  557.  
  558. /*
  559. Получает координаты элемента
  560. */
  561. offset() {
  562. return (this.isString || this.isObject) ? this.element[0].getBoundingClientRect() : this.element.getBoundingClientRect();
  563. }
  564.  
  565. /*
  566. Включает обработчик событий
  567.  
  568. @a - event
  569. @b - если параметр @c является функцией - string selector, иначе function
  570. @c - function
  571. если параметр @c не является функцией или паремтр @b - функция, @c игнорируется
  572.  
  573. $(selector).on('eventName', function(){}) - Для статических элементов
  574. $(document).on('eventName', 'selector', function(){}) - Для динамически созданных элементов
  575. */
  576. on(a, b, c) {
  577. if (typeof c == 'function') {
  578. d.addEventListener(a, function (e) {
  579. let elem = d.querySelectorAll(b);
  580. for (let i = 0; i < elem.length; ++i)
  581. if (e.target == elem[i]) return c.apply(e.target, arguments);
  582. }, false);
  583. } else if (this.isString) {
  584. let i = 0,
  585. self = this,
  586. tmr = setInterval(() => {
  587. if (i < self.element.length) {
  588. self.element[i].addEventListener(a, function (e) {
  589. return b.apply(e.target, arguments);
  590. }, false);
  591. ++i;
  592. } else {
  593. clearInterval(tmr);
  594. }
  595. }, 20);
  596. } else {
  597. this.string.addEventListener(a, function (e) {
  598. return b.apply(e.target, arguments);
  599. }, false);
  600. }
  601. }
  602.  
  603. /*
  604. Получает или изменяет внешний html код элементов
  605.  
  606. @a - string textContent or function
  607. @b - int index
  608. */
  609. outerHtml(a, b) {
  610. a = a || null;
  611. b = b || 0;
  612. if (this.isString || this.isObject) {
  613. if (a) {
  614. for (let i = 0; i < this.element.length; ++i) this.element[i].outerHTML = typeof a == 'function' ? a() : a;
  615. return this;
  616. } else {
  617. return this.element[b].outerHTML;
  618. }
  619. } else {
  620. if (a) {
  621. this.element.outerHTML = typeof a == 'function' ? a() : a;
  622. return this;
  623. } else {
  624. return this.element.outerHTML;
  625. }
  626. }
  627. }
  628.  
  629. /*
  630. Получает родительские элементы
  631.  
  632. @a - string className
  633. если параметр @a указан будут найдены элементы с заданным селектором
  634. */
  635. parent(a) {
  636. b = [];
  637. if (this.isString || this.isObject) {
  638. for (let i = 0; i < this.element.length; ++i){
  639. if(a){
  640. let c = this.element[i].parentNode.parentNode.querySelectorAll(a);
  641. for(let j = 0; j < c.length; ++j) if(c[j] == this.element[i].parentNode) b.push(this.element[i].parentNode);
  642. }else{
  643. b.push(this.element[i].parentNode);
  644. }
  645. }
  646. } else {
  647. if(a){
  648. let c = this.element.parentNode.parentNode.querySelectorAll(a);
  649. for(let j = 0; j < c.length; ++j) if(c[j] == this.element.parentNode) b.push(this.element.parentNode);
  650. }else{
  651. b.push(this.element.parentNode);
  652. }
  653. }
  654. this.element = b;
  655. return this;
  656. }
  657.  
  658. /*
  659. Вставляет textContent или html код в начало элементов
  660.  
  661. @a - string textContent
  662. */
  663. prepend(a) {
  664. if (this.isString) {
  665. for (let i = 0; i < this.element.length; ++i) this.element[i].innerHTML = a + this.element[i].innerHTML;
  666. } else {
  667. this.element.innerHTML = a + this.element.innerHTML;
  668. }
  669. return this;
  670. }
  671.  
  672. /*
  673. Получает предыдущие элементы
  674.  
  675. @a - string className
  676. если параметр @a указан будут найдены элементы с заданным селектором
  677. */
  678. prev(a) {
  679. let b = [];
  680. if (this.isString || this.isObject) {
  681. for (let i = 0; i < this.element.length; ++i){
  682. if(a){
  683. let c = this.element[i].parentNode.querySelectorAll(a);
  684. for(let j = 0; j < c.length; ++j) if(c[j] == this.element[i].previousElementSibling) b.push(this.element[i].previousElementSibling);
  685. }else{
  686. b.push(this.element[i].previousElementSibling);
  687. }
  688. }
  689. } else {
  690. if(a){
  691. let c = this.element.parentNode.querySelectorAll(a);
  692. for(let j = 0; j < c.length; ++j) if(c[j] == this.element.previousElementSibling) b.push(this.element.previousElementSibling);
  693. }else{
  694. b.push(this.element.previousElementSibling);
  695. }
  696. }
  697. this.element = b;
  698. return this;
  699. }
  700.  
  701. /*
  702. Выполняет функцию после загрузки DOM
  703.  
  704. @fn - function
  705. */
  706. ready(fn) {
  707. if (this.string != d || !fn) return;
  708. d.addEventListener('DOMContentLoaded', fn, false);
  709. return true;
  710. }
  711.  
  712. /*
  713. Удаляет элементы
  714. */
  715. remove() {
  716. if (this.isString || this.isObject) {
  717. for (let i = 0; i < this.element.length; ++i) this.element[i].remove();
  718. } else {
  719. this.element.remove();
  720. }
  721. return this;
  722. }
  723.  
  724. /*
  725. Удаляет атрибуты элементов
  726.  
  727. @a - string attribute name
  728. */
  729. removeAttr(a) {
  730. if (this.isString || this.isObject) {
  731. for (let i = 0; i < this.element.length; ++i) this.element[i].removeAttribute(a);
  732. } else {
  733. this.element.removeAttribute(a);
  734. }
  735. return this;
  736. }
  737.  
  738. /* @a - string className */
  739. removeClass(a) {
  740. if (this.isString || this.isObject) {
  741. for (let i = 0; i < this.element.length; ++i) this.element[i].classList.remove(a);
  742. } else {
  743. this.element.classList.remove(a);
  744. }
  745. return this;
  746. }
  747.  
  748. /*
  749. Скролл к заданной позиции или к элементу
  750.  
  751. @a - int position or string selector
  752. @b - int duration ms
  753. @fn - callback function
  754. */
  755. scrollTo(a, b, fn) {
  756. typeof a == 'number' ? scrolling.animateScroll(a, b) : scrolling.scrollTo(d.querySelector(a), b);
  757. return typeof fn == 'function' ? fn() : this;
  758. }
  759.  
  760. /*
  761. Подготавливает данные для отправки через URL
  762. */
  763. serialized() {
  764. let a = (this.isString || this.isObject) ? this.element[0].querySelectorAll('input,select,textarea') : this.element.querySelectorAll('input,select,textarea'),
  765. b = {};
  766. for (let i = 0; i < a.length; ++i) {
  767. if (a[i].type == 'file') {
  768. for (let j = 0; j < a[i].files.length; ++j) b[a[i].getAttribute('name') + j] = a[i].files[j];
  769. } else {
  770. b[a[i].getAttribute('name')] = a[i].value;
  771. }
  772. }
  773. return b;
  774. }
  775.  
  776. /*
  777. Показывает скрытый элемент
  778.  
  779. @a - значение свойства display, по умолчанию block
  780. */
  781. show(a) {
  782. a = a || 'block';
  783. if (this.isString || this.isObject) {
  784. for (let i = 0; i < this.element.length; ++i) this.element[i].style.display = a;
  785. } else {
  786. this.element.style.display = a;
  787. }
  788. return this;
  789. }
  790.  
  791. /*
  792. Возвращает текущую прокрутку окна в px
  793. */
  794. top() {
  795. return this.string == w ? w.scrollY : null;
  796. }
  797.  
  798. /* @a - string className */
  799. toggleClass(a) {
  800. if (this.isString || this.isObject) {
  801. for (let i = 0; i < this.element.length; ++i) this.element[i].classList.toggle(a);
  802. } else {
  803. this.element.classList.toggle(a);
  804. }
  805. return this;
  806. }
  807.  
  808. /*
  809. Вызывает событие
  810.  
  811. @a - event
  812. @b - callback function
  813. */
  814. trigger(a, b) {
  815. if (typeof a == 'undefined') return;
  816. if (this.string == w) {
  817. w.dispatchEvent(new Event(a));
  818. } else if (this.string == d) {
  819. d.dispatchEvent(new Event(a));
  820. } else if (this.isString || this.isObject) {
  821. for (let i = 0; i < this.element.length; ++i) this.element[0].dispatchEvent(new Event(a));
  822. } else {
  823. this.element.dispatchEvent(new Event(a));
  824. }
  825. if(typeof b == 'function') b();
  826. return this;
  827. }
  828.  
  829. /*
  830. Получает или устанавливает значение в HTMLInputElement
  831.  
  832. @a - value
  833. */
  834. val(a) {
  835. a = typeof a != 'undefined' ? a : null;
  836. if (this.isString || this.isObject) {
  837. if (a||a==='') {
  838. for (let i = 0; i < this.element.length; ++i) this.element[i].value = a;
  839. return true;
  840. } else {
  841. return this.element[0].value;
  842. }
  843. } else {
  844. return a||a==='' ? (this.element.value = a, true) : this.element.value;
  845. }
  846. }
  847.  
  848. /*
  849. Производит валидацию полей
  850. */
  851. validated() {
  852. let b = (this.element[0] || this.element).querySelectorAll('input,select,textarea'),
  853. c = 0;
  854. for (let key in b) {
  855. if (isFinite(key)) {
  856. let k = b[key],
  857. valid = k.validity,
  858. error = k.getAttribute('error');
  859. if (k.required) {
  860. if (k.tagName === 'INPUT') {
  861. if (k.type === 'number') {
  862. if (k.min && valid.rangeUnderflow) {
  863. error = error || 'Минимальное значение поля ' + k.min;
  864. ++c;
  865. }
  866. if (k.max && valid.rangeOverflow) {
  867. error = error || 'Максимальное значение поля ' + k.max;
  868. ++c;
  869. }
  870. } else if (k.type === 'tel') {
  871. let kv=k.value,kvl=kv.length;
  872. 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))){
  873. error = error || 'Некорректный номер телефона<br>пример: +79123456789,89123456789,88001234567 или 642531';
  874. ++c;
  875. }
  876. } else if (k.type === 'email') {
  877. if (valid.typeDismatch) {
  878. error = error || 'Некорректный ввод email<br>пример: name@mailserver.ru';
  879. ++c;
  880. }
  881. }
  882. if (k.pattern && valid.patternMismatch) {
  883. error = error || 'Проверьте правильность заполнения полей';
  884. ++c;
  885. }
  886. if (valid.typeDismatch) {
  887. error = error || 'Некорректное значение "' + k.value + '"';
  888. ++c;
  889. }
  890. }
  891. if (valid.valueMissing) {
  892. error = error || 'Обязательные поля не заполнены';
  893. ++c;
  894. }
  895. if (c > 0) {
  896. d.querySelector('.modal_info').innerHTML = (error || 'Проверьте правильность заполнения полей');
  897. fn.modal({
  898. over: null,
  899. box: '.modal_event',
  900. close: 3
  901. });
  902. return false;
  903. }
  904. }
  905. }
  906. }
  907. return true;
  908. }
  909. }
  910.  
  911. /* вспомогательный класс */
  912. class Set {
  913.  
  914. /*
  915. Выполняет Ajax запрос
  916.  
  917. @a - object settings
  918. @b and @c - empty, ignored
  919. */
  920. ajax(a, b, c) {
  921. c = new XMLHttpRequest(), b = {
  922. type: 'POST',
  923. url: null,
  924. success: null,
  925. json: true,
  926. error: null,
  927. files: null,
  928. callback: null,
  929. asinc: true,
  930. data: null
  931. };
  932. for (let f in b) b[f] = typeof a[f] != 'undefined' ? a[f] : b[f];
  933. a = null;
  934. c.open(b.type, b.url, b.asinc);
  935. c.onreadystatechange = function () {
  936. try {
  937. if (this.readyState !== 4 || this.status !== 200) return;
  938. if (b.success)
  939. if (b.json) {
  940. b.success(JSON.parse(this.responseText));
  941. } else {
  942. b.success(this.responseText);
  943. }
  944. } catch (e) {
  945. if (b.error) b.error(e);
  946. }
  947. };
  948. if (b.files) {
  949. c.send(this.formFiles(b.data));
  950. } else {
  951. c.send(this.form(b.data));
  952. }
  953. return typeof b.callback == 'function' ? b.callback() : this;
  954. }
  955.  
  956. /*
  957. Устанавливает фоновое изображение в элементе @a
  958.  
  959. @a - string selector or HTMLElement or HTMLElementCollection
  960. @b - file
  961. */
  962. bgImage(a, b) {
  963. if (b.type.match(/image.*/)) {
  964. let reader = new FileReader();
  965. reader.onload = function (e) {
  966. $(a).css({'background-image': 'url(' + e.target.result + ')'});
  967. };
  968. reader.readAsDataURL(b);
  969. }
  970. }
  971.  
  972. /*
  973. Копирует данные в буфер обмена. Внимание, копирование не будет произведено если для body указано свойство user-select: none
  974.  
  975. @a - string copy data
  976. */
  977. copy(a) {
  978. if (!a || a == 'undefined') return false;
  979. let b, c = d.createElement('input');
  980. c.value = a;
  981. d.body.append(c);
  982. c.select();
  983. if (d.execCommand('copy')) {
  984. b = true;
  985. } else {
  986. b = false;
  987. }
  988. w.getSelection().removeAllRanges();
  989. c.remove();
  990. localStorage.setItem('clip', a);
  991. return b;
  992. }
  993.  
  994. /*
  995. Инициализирует счетчик чисел от 0 до заданного
  996.  
  997. @a - HTMLElement
  998. */
  999. countPlus(a) {
  1000. let b = {},
  1001. c = 0,
  1002. f = a.dataset;
  1003. b.step = parseFloat(f.count / 100);
  1004. setTimeout(function () {
  1005. b.fn = setInterval(function () {
  1006. if (c + b.step >= parseFloat(f.count)) {
  1007. a.innerHTML = f.count;
  1008. clearInterval(b.fn);
  1009. }
  1010. c += b.step;
  1011. a.innerHTML = parseInt(c);
  1012. }, f.duration / 100);
  1013. }, f.delay);
  1014. }
  1015.  
  1016. /*
  1017. Собирает данные в объект FormData
  1018.  
  1019. @a - object data
  1020. @b - FormData
  1021. */
  1022. form(a, b) {
  1023. b = b || new FormData();
  1024. for (let key in a)
  1025. if (a.hasOwnProperty(key)) b.append(key, a[key]);
  1026. return b;
  1027. }
  1028.  
  1029. /*
  1030. Собирает файлы в объект FormData
  1031.  
  1032. @a - array files
  1033. @b - FormData
  1034. */
  1035. formFiles(a, b) {
  1036. b = b || new FormData();
  1037. for (let i = 0; i < a.length; ++i) b.append('file[' + i + ']', a[i]);
  1038. return b;
  1039. }
  1040.  
  1041. /*
  1042. Создает изображение и добавляет его в конец элемента @a
  1043.  
  1044. @a - string selector or HTMLElement
  1045. @b - file
  1046. */
  1047. image(a, b) {
  1048. if (b.type.match(/image.*/)) {
  1049. let reader = new FileReader();
  1050. reader.onload = function (e) {
  1051. let img = d.createElement('img');
  1052. img.src = e.target.result;
  1053. $(a).after(img);
  1054. };
  1055. reader.readAsDataURL(b);
  1056. }
  1057. }
  1058.  
  1059. /*
  1060. Создает превью из файлов элемента @a, добавляет их в элемент @c и выводит информацию о файлах в элемент @b
  1061.  
  1062. @a - HTMLInputElement type file
  1063. @b - selector text element
  1064. @c - selector preview element
  1065. */
  1066. imgPreview(a, b, c) {
  1067. let f = a.files;
  1068. if (f.length) {
  1069. $(c).empty();
  1070. [].forEach.call(f, function (file) {
  1071. if (file.type.match(/image.*/)) {
  1072. let reader = new FileReader();
  1073. reader.onload = function (e) {
  1074. var img = d.createElement('img');
  1075. img.src = e.target.result;
  1076. $(c).after(img);
  1077. };
  1078. reader.readAsDataURL(file);
  1079. }
  1080. });
  1081. $(b).html(f.length == 1 ? f[0].name + ' (' + (f[0].size / 1024).toFixed(2) + ' Кб)' : 'Добавлено ' + f.length + ' файлов');
  1082. } else {
  1083. h.innerHTML('Выберите файл');
  1084. $(c).html('Предпросмотр');
  1085. }
  1086. return this;
  1087. }
  1088.  
  1089. /*
  1090. Разбирает строку JSON
  1091.  
  1092. @a - json object
  1093. */
  1094. json(a) {
  1095. return JSON.parse(a);
  1096. }
  1097.  
  1098. /*
  1099. Превращает объекты в строку в формате JSON
  1100.  
  1101. @a - json object
  1102. */
  1103. jstr(a) {
  1104. return JSON.stringify(a);
  1105. }
  1106.  
  1107. /*
  1108. Вывод данных в консоль для отладки
  1109. */
  1110. log() {
  1111. for (let i = 0; i < arguments.length; ++i) console.info(arguments[i]);
  1112. return this;
  1113. }
  1114.  
  1115. /*
  1116. Производит манипуляции с модальными окнами
  1117.  
  1118. @a - object settings
  1119. */
  1120. modal(a) {
  1121. let b = {
  1122. action: 'open',
  1123. over: '.modal_overlay',
  1124. box: null,
  1125. old: null,
  1126. new: null,
  1127. close: null,
  1128. callback: null
  1129. };
  1130. for (let c in b) b[c] = typeof a[c] != 'undefined' ? a[c] : b[c];
  1131. a = null;
  1132. if (b.action == 'open') {
  1133. if (!b.box) return;
  1134. if (b.over) $(b.over).fadeIn();
  1135. $(b.box).fadeIn();
  1136. if (b.close) {
  1137. setTimeout(() => {
  1138. if (b.over) $(b.over).fadeOut();
  1139. $(b.box).fadeOut();
  1140. }, b.close * 1000);
  1141. }
  1142. } else if (b.action == 'close') {
  1143. $(b.over).fadeOut();
  1144. $('.modal').each(function () {
  1145. if (this.style.display == 'block') $(this).fadeOut();
  1146. });
  1147. } else if (b.action == 'change') {
  1148. if (!b.old || !b.new) return;
  1149. $(b.old).fadeOut();
  1150. $(b.new).fadeIn();
  1151. }
  1152. return typeof b.callback == 'function' ? b.callback() : this;
  1153. }
  1154.  
  1155. /*
  1156. Имитирует сон скрипта
  1157.  
  1158. @a - int sleep time ms
  1159. @fn - callback function
  1160. */
  1161. sleep(a, fn) {
  1162. setTimeout(fn || function() {}, a);
  1163. return this;
  1164. }
  1165.  
  1166. /*
  1167. Транслитерация введенных данных (ru => en)
  1168.  
  1169. @a - string data
  1170. @b - ignored
  1171. */
  1172. translite(a, b) {
  1173. let c = typeof b != 'undefined' ? {} : {
  1174. 'а': 'a',
  1175. 'б': 'b',
  1176. 'в': 'v',
  1177. 'г': 'g',
  1178. 'д': 'd',
  1179. 'е': 'e',
  1180. 'ж': 'g',
  1181. 'з': 'z',
  1182. 'и': 'i',
  1183. 'й': 'y',
  1184. 'к': 'k',
  1185. 'л': 'l',
  1186. 'м': 'm',
  1187. 'н': 'n',
  1188. 'о': 'o',
  1189. 'п': 'p',
  1190. 'р': 'r',
  1191. 'с': 's',
  1192. 'т': 't',
  1193. 'у': 'u',
  1194. 'ф': 'f',
  1195. 'ы': 'i',
  1196. 'э': 'e',
  1197. 'А': 'A',
  1198. 'Б': 'B',
  1199. 'В': 'V',
  1200. 'Г': 'G',
  1201. 'Д': 'D',
  1202. 'Е': 'E',
  1203. 'Ж': 'G',
  1204. 'З': 'Z',
  1205. 'И': 'I',
  1206. 'Й': 'Y',
  1207. 'К': 'K',
  1208. 'Л': 'L',
  1209. 'М': 'M',
  1210. 'Н': 'N',
  1211. 'О': 'O',
  1212. 'П': 'P',
  1213. 'Р': 'R',
  1214. 'С': 'S',
  1215. 'Т': 'T',
  1216. 'У': 'U',
  1217. 'Ф': 'F',
  1218. 'Ы': 'I',
  1219. 'Э': 'E',
  1220. 'ё': 'yo',
  1221. 'х': 'h',
  1222. 'ц': 'ts',
  1223. 'ч': 'ch',
  1224. 'ш': 'sh',
  1225. 'щ': 'shch',
  1226. 'ъ': '',
  1227. 'ь': '',
  1228. 'ю': 'yu',
  1229. 'я': 'ya',
  1230. 'Ё': 'YO',
  1231. 'Х': 'H',
  1232. 'Ц': 'TS',
  1233. 'Ч': 'CH',
  1234. 'Ш': 'SH',
  1235. 'Щ': 'SHCH',
  1236. 'Ъ': '',
  1237. 'Ь': '',
  1238. 'Ю': 'YU',
  1239. 'Я': 'YA',
  1240. ' ': '_',
  1241. ' ': '_',
  1242. '.': '_',
  1243. '..': '_',
  1244. ',': '_',
  1245. '?': '_',
  1246. '??': '_',
  1247. '!': '_',
  1248. '!!': '_',
  1249. '-': '_',
  1250. '--': '_',
  1251. '=': '_',
  1252. '+': '_',
  1253. '__': '_'
  1254. };
  1255. return a.replace(/[\s\S]/g, (x) => {
  1256. if (c.hasOwnProperty(x)) return c[x];
  1257. return x;
  1258. });
  1259. }
  1260.  
  1261. /*
  1262. Открывает дополнительные вкладки или окна браузера с заданным URL
  1263.  
  1264. @a - object settings
  1265. */
  1266. window(a) {
  1267. let b = {
  1268. width: w.screen.width,
  1269. height: w.screen.height,
  1270. url: null,
  1271. x: w.screen.width / 2,
  1272. y: w.screen.height / 2,
  1273. callback: null,
  1274. full: 0,
  1275. tool: 0,
  1276. status: 0,
  1277. menu: 0,
  1278. resize: 0,
  1279. focus: true
  1280. };
  1281. for (let c in b) b[c] = typeof a[c] != 'undefined' ? a[c] : b[c];
  1282. 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);
  1283. e.blur();
  1284. if (b.url) e.location.href = b.url;
  1285. e.moveTo(b.x, b.y);
  1286. if (b.focus) e.focus();
  1287. if (typeof b.callback == 'function') b.callback();
  1288. return e;
  1289. }
  1290. }
  1291.  
  1292. /* класс слайдера */
  1293. class Slider {
  1294.  
  1295. /*
  1296. Инициализация класса
  1297.  
  1298. @a - string selector or object HTMLCollection
  1299. */
  1300. constructor(a) {
  1301. this.string = a || null;
  1302. this.box = typeof this.string == 'string' ? d.querySelectorAll(this.string) : (this.string || null);
  1303. }
  1304.  
  1305. /*
  1306. Инициализация слайдера
  1307.  
  1308. @a - object settings
  1309. */
  1310. init(a) {
  1311. if (!this.box.length) return;
  1312. a = a || {};
  1313. let b = {
  1314. delay: 2000,
  1315. dots: true,
  1316. dots_list: [],
  1317. autoplay: true,
  1318. currentSlide: 0,
  1319. interval: null,
  1320. before: null,
  1321. callback: null
  1322. },
  1323. self = this;
  1324. for (let c in b) this[c] = typeof a[c] != 'undefined' ? a[c] : b[c];
  1325. this.slides = d.querySelector(this.string).children;
  1326. this.length = this.slides.length;
  1327. if (this.dots === true) {
  1328. let br = d.createElement('ul');
  1329. br.className = 'slider_dots';
  1330. for (let i = 0; i < this.length; ++i) {
  1331. let brs = d.createElement('li');
  1332. brs.setAttribute('data-slide', i);
  1333. brs.className = 'slider_dot';
  1334. br.appendChild(brs);
  1335. }
  1336. d.querySelector(this.string).parentNode.appendChild(br);
  1337. this.dots_list = d.querySelector('.slider_dots').children;
  1338. }
  1339. this.slides[this.currentSlide].classList.add('slide_active');
  1340. if (this.dots) this.dots_list[this.currentSlide].classList.add('dot_active');
  1341. if (this.autoplay === true) this.start();
  1342. return this;
  1343. }
  1344.  
  1345. /*
  1346. Старт автоматического пролистывания
  1347. */
  1348. start() {
  1349. this.interval = w.setInterval(() => this.next(), this.delay);
  1350. }
  1351.  
  1352. /*
  1353. Остановка автоматического пролистывания
  1354. */
  1355. stop() {
  1356. w.clearInterval(this.interval);
  1357. this.interval = null;
  1358. }
  1359.  
  1360. /*
  1361. Переход к предыдущему слайду
  1362. */
  1363. prev() {
  1364. if (!this.box.length) return;
  1365. this.go(this.currentSlide - 1);
  1366. }
  1367.  
  1368. /*
  1369. Переход к следующему слайду
  1370. */
  1371. next() {
  1372. if (!this.box.length) return;
  1373. this.go(this.currentSlide + 1);
  1374. }
  1375.  
  1376. /*
  1377. Переход к заданному слайду
  1378.  
  1379. @n - int need slide
  1380. */
  1381. go(n) {
  1382. if (!this.box.length) return;
  1383. if (typeof this.before == 'function') this.before();
  1384. this.slides[this.currentSlide].classList.remove('slide_active');
  1385. if (this.dots) this.dots_list[this.currentSlide].classList.remove('dot_active');
  1386. this.currentSlide = parseInt((n + this.length) % this.length);
  1387. this.slides[this.currentSlide].classList.add('slide_active');
  1388. if (this.dots) this.dots_list[this.currentSlide].classList.add('dot_active');
  1389. return typeof this.callback == 'function' ? this.callback() : this;
  1390. }
  1391. }
  1392.  
  1393. /* Инициализация глобальных переменных */
  1394. if(typeof $ != 'undefined'){
  1395. w.jCool = (a) => new App(a);
  1396. }else{
  1397. w.$ = (a) => new App(a);
  1398. }
  1399. w.fn = new Set();
  1400. w.sl = (a) => new Slider(a);
  1401. })(window, document);
  1402.  
  1403. /*!
  1404. * CoolJS JavaScript Library v2.6
  1405. * https://coolcms.ru/
  1406. * https://vk.com/fastgrid
  1407. *
  1408. * Copyright Dmitry Kokorin
  1409. * Released under the MIT license
  1410. * https://coolcms.ru/license/
  1411. *
  1412. * Documentation: https://coolcms.ru/docs/5-cool_js
  1413. * Date: 2018-01-20T17:24Z
  1414. */