'use strict'; /* add support indexOf(), match() to SVGAnimatedString */ SVGAnimatedString.prototype.indexOf = SVGAnimatedString.prototype.indexOf || function(){ return String.prototype.indexOf.apply(this.baseVal, arguments); }; SVGAnimatedString.prototype.match = SVGAnimatedString.prototype.match || function(){ return String.prototype.match.apply(this.baseVal, arguments); }; function rokna_onmouse(event) { var ev = event || { type: '', target: document.body.parentNode }; if( ev.type == 'mousedown' && (rokna_onmouse.ev||{}).type == 'touchstart' && (rokna_onmouse.ev||{}).target == ev.target) return; // подавляем эмуляцию mousedown после touchstart rokna_onmouse.ev = (ev instanceof Event) ? ev : rokna_onmouse.ev; // сохраним для расширений и для подавления touchstart+mousedown if (ev.type == 'touchstart' || ev.type == 'touchmove' || ev.type == 'touchend' || ev.type == 'touchcancel') { // трансформируем touch-события в события мыши var orig_ev = ev, touch0 = ev.targetTouches[0]||{}; ev = { type: ({touchstart:'mousedown', touchmove: 'mousemove', touchend: 'mouseup', touchcancel: 'mouseup'})[ev.type], target: touch0.target || ev.target, pageX: touch0.pageX || 0, pageY: touch0.pageY || 0, clientX: touch0.clientX || 0, clientY: touch0.clientY || 0, originalEvent: orig_ev, preventDefault: function(){ /* orig_ev.preventDefault();*/ } }; } else if( ev.type == 'mouseout' && ev instanceof Event) { // поддержка out of window var e = ev.originalEvent || ev; // if jQuery.Event var active_node = (e.relatedTarget) ? e.relatedTarget : e.toElement; if(!active_node) rokna_onmouse({type: 'mouseout-window', target: ev.target, originalEvent: ev}); return; } var trg1 = ev.target || ev.srcElement || document.body.parentNode; if (trg1.nodeType && trg1.nodeType == 9) trg1 = trg1.body.parentNode; // #DOCUMENT if (trg1.nodeType && trg1.nodeType == 3) trg1 = trg1.parentNode; // #TEXT var trg1p = (trg1.parentNode && trg1.parentNode.nodeType != 9) ? trg1.parentNode : {className:'', nodeName:'', getAttribute:function(){return ''}}; // [click] если нас назначили на click -> подавим click if ( ev.type == 'click' ) { try { ev.preventDefault(); } catch(ex){ console.info(ex.stack); }; try { ev.stopPropagation(); } catch(ex){ console.info(ex.stack); }; // console.log('click captured'); alert('click captured'); window.removeEventListener('click', rokna_onmouse, true); rokna_onmouse.click_cancel_active = false; // console.log('removed click capturing'); return false; } // [mousedown] .js-rokna-prev-slide if ( ev.type == 'mousedown' && (trg1.className.indexOf('js-rokna-prev-slide') > -1 || trg1p.className.indexOf('js-rokna-prev-slide') > -1) || ev.type == 'js-rokna-prev-slide') { var trg = trg1p.className.indexOf('js-rokna-prev-slide') > -1 ? trg1p : trg1; if (!trg.dataset.slider) console.warn('data-slider attribute not found!', trg); var slider = document.querySelector(trg.dataset.slider) || document.getElementById(trg.dataset.slider) || document.querySelector('.'+trg.dataset.slider); if (slider) { var step = ev.slidesToScroll || ev['slides-to-scroll'] || trg.dataset.slidesToScroll || 1; var selected_slide_num = parseInt(((slider||{}).dataset||{}).selectedSlideNum||'0'); if (isNaN(selected_slide_num)) selected_slide_num = 0; if (slider.dataset.sliderInfinite || slider.dataset.sliderInfinity) { if (!slider.slideCount) rokna_onmouse({type: 'slider-infinite-initialize', target: slider}); var next_slide_num = selected_slide_num-step < 0 ? selected_slide_num-step + slider.dataset.slideCount*1 : selected_slide_num-step; } else var next_slide_num = Math.max(selected_slide_num-step, 0); // console.log('[mousedown] .js-rokna-prev-slide', trg, slider, selected_slide_num, step); // проставим значение rokna_onmouse.move_direction = 1; rokna_onmouse({ type: 'slider-select', target: slider, slideNum: next_slide_num }); } try { ev.preventDefault(); } catch(ex){ /* silent */ }; return; } // [mousedown] .js-rokna-next-slide if ( ev.type == 'mousedown' && (trg1.className.indexOf('js-rokna-next-slide') > -1 || trg1p.className.indexOf('js-rokna-next-slide') > -1) || ev.type == 'js-rokna-next-slide') { var trg = trg1p.className.indexOf('js-rokna-next-slide') > -1 ? trg1p : trg1; if (!trg.dataset.slider) console.warn('data-slider attribute not found!', trg); var slider = document.querySelector(trg.dataset.slider) || document.getElementById(trg.dataset.slider) || document.querySelector('.'+trg.dataset.slider); if (slider) { var step = ev.slidesToScroll || ev['slides-to-scroll'] || trg.dataset.slidesToScroll || 1; var selected_slide_num = parseInt((slider.dataset||{}).selectedSlideNum||'0'); if (isNaN(selected_slide_num)) selected_slide_num = 0; if (slider.dataset.sliderInfinite || slider.dataset.sliderInfinity) { if (!slider.slideCount) rokna_onmouse({type: 'slider-infinite-initialize', target: slider}); var next_slide_num = selected_slide_num+step >= slider.dataset.slideCount*1 ? selected_slide_num+step - slider.dataset.slideCount : selected_slide_num+step; } else var next_slide_num = Math.min(selected_slide_num+step, slider.dataset.slideCount || slider.children.length); // console.log('[mousedown] .js-rokna-next-slide', trg, slider, selected_slide_num, step); // не забываем про направление rokna_onmouse.move_direction = -1; rokna_onmouse({ type: 'slider-select', target: slider, slideNum: next_slide_num }); } try { ev.preventDefault(); } catch(ex){ /* silent */ }; return; } // [mousedown] .js-rokna-switch-dot if ( ev.type == 'mousedown' && (trg1.className.indexOf('js-rokna-switch-dot') > -1 || trg1p.className.indexOf('js-rokna-switch-dot') > -1)) { var dot = trg1p.className.indexOf('js-rokna-switch-dot') > -1 ? trg1p : trg1; // к какому слайдеру эти кнопки относятся? var slider = dot.dataset.slider ? document.querySelector(dot.dataset.slider) : undefined; if (!slider) { var sliders = document.querySelectorAll('.js-rokna-slider'); for (var i=0; i 0) var slide_num = parseInt(dot.dataset.slideNum.split(/, */)[0])-1; // указан один слайд else var slide_num = parseInt(dot.dataset.slideNum)-1; // не забываем про направление rokna_onmouse.move_direction = slide_num < (slider.dataset.selectedSlideNum||0) ? 1 : -1; rokna_onmouse.move_direction = undefined; // так-же обновим метку времени для autoplay slider.dataset.autoplayTimestamp = (new Date())*1; // console.log('[mousedown] .js-rokna-switch-dot', slide_num, slider); rokna_onmouse({ type: 'slider-select', target: slider, slideNum: slide_num }); } } // [mousedown] .js-rokna-slider if ( ev.type == 'mousedown' ) { // внутри слайдера? var slider, selected_slide; for (var trg = trg1; trg.parentNode; trg = trg.parentNode) { if ((trg.className||'').indexOf('js-rokna-slider') > -1) { slider = trg; break; } // кнопки мы не обслуживаем if ((trg.className||'').match(/(js-rokna-switch-dot|js-rokna-prev-slide|js-rokna-next-slide)/)) { slider = undefined; break; } // на какой слайд нажали? if ((trg.className||'').indexOf('js-rokna-slide') > -1) { selected_slide = trg; continue; } } // Responsive if (slider && slider.dataset.sliderResponsive) try { var responsive = eval('({'+slider.dataset.sliderResponsive+'})'); var suiteble_w; for (var w in responsive) { if (window.innerWidth <= parseInt(w) && (!suiteble_w || parseInt(suiteble_w) > parseInt(w))) suiteble_w = w; } if (suiteble_w) { // слайдер должен быть отключен? if (responsive[suiteble_w].active === false) slider = undefined; } } catch(ex) { console.error(ex.stack); } // console.log('[mousedown] .js-rokna-slider', slider, trg1); // если внутри слайдера, то активируем отслеживание движений мыши if (slider && (selected_slide || slider == trg1)) { // подключаем свои обработчики событий if (!rokna_onmouse.mousemove_handler_active) { document.documentElement.addEventListener('mousemove', rokna_onmouse); document.documentElement.addEventListener('touchmove', rokna_onmouse); document.documentElement.addEventListener('mouseout', rokna_onmouse); rokna_onmouse.mousemove_handler_active = true; } if (!rokna_onmouse.mouseup_handler_active) { document.documentElement.addEventListener('mouseup', rokna_onmouse); document.documentElement.addEventListener('touchend', rokna_onmouse); document.documentElement.addEventListener('touchcancel', rokna_onmouse); rokna_onmouse.mouseup_handler_active = true; } // если осталось включено подавление click -> отключим его if (rokna_onmouse.click_cancel_active == true) { window.removeEventListener('click', rokna_onmouse, true); rokna_onmouse.click_cancel_active = false; } // сохраним активный прокручиваемый слайдер rokna_onmouse.current_slider = slider; // останавливаем анимацию rokna_onmouse({type: 'slider-stop-animate', target: slider}); // активируем infinitе если надо if (slider.dataset.sliderInfinite || slider.dataset.sliderInfinity) { rokna_onmouse({type: 'slider-infinite-initialize', target: slider}); } // сохраняем стартовые кординаты rokna_onmouse.startPageX = ev.clientX; rokna_onmouse.startPageY = ev.clientY; // запомним текущую прокрутку слайдера rokna_onmouse.slider_transform = ((slider.style.transform||'').match(/translate3d\((-?[0-9]+)/)||[0,'0'])[1]; // touchThreshold rokna_onmouse.touchThreshold = parseInt(slider.dataset.sliderTouchThreshold || '10'); // document.querySelector('.header2__mobile-phone-link').innerHTML = slider.dataset.touchThreshold; // отменим стандартную обработку события броузером try { ev.preventDefault(); } catch(ex) { /* silence */ } // return false; } } // [mousemove] .js-rokna-slider if ( ev.type == 'mousemove' && rokna_onmouse.current_slider) { var slider = rokna_onmouse.current_slider; var ev_pageX = ev.clientX; var ev_pageY = ev.clientY; var start_transformX = isNaN(parseInt(rokna_onmouse.slider_transform)) ? 0 : parseInt(rokna_onmouse.slider_transform); var delta_pageX = ev_pageX - rokna_onmouse.startPageX; var delta_pageY_abs = Math.abs(ev_pageY - rokna_onmouse.startPageY); //console.log('[mousemove] .js-rokna-slider', delta_pageX, delta_pageY, rokna_onmouse.touchThreshold*1); // touch up/down threshold if (rokna_onmouse.touchThreshold !== 0 && delta_pageY_abs > Math.abs(delta_pageX) && delta_pageY_abs >= rokna_onmouse.touchThreshold*1) { rokna_onmouse.touchThreshold = 9999; // блокируем движение слайдов } else // touchThreshold if (Math.abs(delta_pageX) >= rokna_onmouse.touchThreshold*1) { rokna_onmouse.touchThreshold = 0; // отключаем // передвигаем все слайды rokna_onmouse.current_slider.style.transform = 'translate3d('+(start_transformX+delta_pageX)+'px, 0px, 0px)'; // вычесляем направление прокрутки rokna_onmouse.move_direction = delta_pageX; try { if(ev.originalEvent) ev.originalEvent.preventDefault(); } catch(ex){ console.info(ex.stack); }; } } // [mouseup] .js-rokna-slider if ( ev.type == 'mouseup' || ev.type == 'mouseout-window') { if(rokna_onmouse.mousemove_handler_active) { document.documentElement.removeEventListener('mousemove', rokna_onmouse); document.documentElement.removeEventListener('touchmove', rokna_onmouse); document.documentElement.removeEventListener("mouseout", rokna_onmouse); rokna_onmouse.mousemove_handler_active = false; } if(rokna_onmouse.mouseup_handler_active) { document.documentElement.removeEventListener('mouseup', rokna_onmouse); document.documentElement.removeEventListener('touchend', rokna_onmouse); document.documentElement.removeEventListener('touchcancel', rokna_onmouse); rokna_onmouse.mouseup_handler_active = false; } // подавляем click if(rokna_onmouse.current_slider && rokna_onmouse.touchThreshold === 0 && !rokna_onmouse.click_cancel_active) { rokna_onmouse.click_cancel_active = true; window.addEventListener('click', rokna_onmouse, true); // не всегда обработчик срабатывает после mouseup -> проверим и отключим по timeout (характерно для mobile) setTimeout(function(){ if(rokna_onmouse.click_cancel_active) rokna_onmouse.click_cancel_active = window.removeEventListener('click', rokna_onmouse, true); }, 200), false; } if (rokna_onmouse.current_slider) { var slider = rokna_onmouse.current_slider; rokna_onmouse.current_slider = undefined; // так-же обновим метку времени для autoplay slider.dataset.autoplayTimestamp = (new Date())*1; /* если есть слайдер -> выравниваем слайды по левому краю */ // сдвиг слайдов var slider_transformX = parseInt((slider.style.transform||'').substring(12)); for (var i=0; i < slider.children.length; i++) if (slider.children[i].className.indexOf('js-rokna-slide') > -1) { // SVG if (slider.children[i].offsetLeft === undefined) { var slider_bbox = slider_bbox || slider.getBoundingClientRect(); var slide_bbox = slider.children[i].getBoundingClientRect(); var slide_offsetLeft = slide_bbox.left - slider_bbox.left; var slide_offsetWidth = slide_bbox.width; } else { var slide_offsetLeft = slider.children[i].offsetLeft; var slide_offsetWidth = slider.children[i].offsetWidth; } // пропускаем полностью прокрученные слайды if( slider_transformX + slide_offsetLeft + slide_offsetWidth < 0) continue; // console.log('trfrmX='+slider_transformX +' slideLeft='+ slider.children[i].offsetLeft +' trX-slideLeft='+ Math.abs(slider_transformX + slider.children[i].offsetLeft) +' w/2='+ slider.children[i].offsetWidth/2); // более чем на половину скрыт слева? var slide_half_hidden = Math.abs(slider_transformX + slide_offsetLeft) > slider.children[i].scrollWidth/2; // запределы левого края нельзя -> прижимаем к левому краю if (slider_transformX >= 0) { rokna_onmouse({ type: 'slider-select', target: slider, slideNum: slider.children[i].dataset.slideNum || 0 }); break; } // допрокручиваем слайд в зависимости от направления прокрутки // move_direction ++ прокрутка назад else if (rokna_onmouse.move_direction > 10 // порог срабатывания && Math.abs(rokna_onmouse.move_direction) < slider.children[i].scrollWidth/2 // если микро прокрутка ) { // докручиваем левый слайд rokna_onmouse({ type: 'slider-select', target: slider, slideNum: slider.children[i].dataset.slideNum || i }); break; } // move_direction -- прокрутка вперёд else if (rokna_onmouse.move_direction < -10 // порог срабатывания && Math.abs(rokna_onmouse.move_direction) < slider.children[i].scrollWidth/2 // если микро прокрутка && slider.children[i+1] // если есть куда прокручивать ) { rokna_onmouse({ type: 'slider-select', target: slider, slideNum: slider.children[i+1].dataset.slideNum || i+1 }); break; } // наполовину скрытые слева допракручиваем на лево else if (slide_half_hidden && slider.children[i].nextElementSibling && slider.children[i].nextElementSibling.className.indexOf('js-rokna-slide') > -1) { rokna_onmouse({ type: 'slider-select', target: slider, slideNum: slider.children[i+1].dataset.slideNum || i+1 }); break; } // просто выравниваем текущий слайд else { rokna_onmouse({ type: 'slider-select', target: slider, slideNum: slider.children[i].dataset.slideNum || i }); break; } } // try { ev.preventDefault(); } catch(ex){ console.info(ex.stack); }; // try { ev.stopPropagation(); } catch(ex){ console.info(ex.stack); }; } } // [slider-autoplay] if ( ev.type == 'slider-autoplay' && !rokna_onmouse.current_slider) { if (trg1.className.indexOf('js-rokna-slider') < 0) { console.warn('event.target is not a slider!'); return; } // активируем infinitе если надо if (trg1.dataset.sliderInfinite || trg1.dataset.sliderInfinity) { rokna_onmouse({type: 'slider-infinite-initialize', target: trg1}); } // если мышь над слайдером или страница не активка -> паузим смену слайдов if (trg1.querySelector(':hover') || document.visibilityState == 'hidden') { trg1.dataset.autoplayTimestamp = (new Date())*1 - (ev.autoplay || parseInt(trg1.dataset.sliderAutoplay || '4000')) / 2; return; } // последняя смена слайда когда была? var autoplay_timestamp = parseInt(trg1.dataset.autoplayTimestamp||'0'); if(autoplay_timestamp == 0 || isNaN(autoplay_timestamp)) autoplay_timestamp = trg1.dataset.autoplayTimestamp = (new Date())*1; // настало время смены слайда? var autoplay_interval = ev.autoplay || parseInt(trg1.dataset.sliderAutoplay || '4000'); if (autoplay_interval > 0 && autoplay_timestamp+autoplay_interval < (new Date())*1) { rokna_onmouse.move_direction = -1; var slide_num = parseInt(trg1.dataset.selectedSlideNum||'0'); var slides = trg1.querySelectorAll('.js-rokna-slide:not(.js-rokna-cloned)'); // переключим на след. если есть if(slides[slide_num+1]) { rokna_onmouse({ type: 'slider-select', target: trg1, slideNum: slide_num+1 }); } // либо на первый else { rokna_onmouse({ type: 'slider-select', target: trg1, slideNum: 0 }); } // обновим метку autoplay trg1.dataset.autoplayTimestamp = (new Date())*1; } } // [slider-select] if ( ev.type == 'slider-select' ) { // ищем выбранный слайд и 0ой оригинал var first_slide, slide; for(var i=0; i -1) { if (trg1.children[i].className.indexOf('js-rokna-cloned') > -1) continue; if (!first_slide) first_slide = trg1.children[i]; if((trg1.children[i].dataset.slideNum||i) == ev.slideNum) { slide = trg1.children[i]; break; } } // не нашли слайд? if (!slide) { console.warn('Slide '+ev.slideNum+' not available!'); return; } // SVG if (slide.offsetLeft === undefined || first_slide.offsetLeft === undefined) { var slider_bbox = trg1.getBoundingClientRect(); var slide_offsetLeft = slide.offsetLeft || slide.getBoundingClientRect().left - slider_bbox.left; var first_slide_offsetLeft = first_slide.offsetLeft || first_slide.getBoundingClientRect().left - slider_bbox.left; } else { var slide_offsetLeft = slide.offsetLeft; var first_slide_offsetLeft = first_slide.offsetLeft; } // смещение слайдера var slider_transformX = parseInt((trg1.style.transform||'').substring(12) || '0'); // отладочный вывод // console.log(trg1.dataset.selectedSlideNum + ' -> ' + ev.slideNum, rokna_onmouse.move_direction, slide); // Infinite if (trg1.dataset.sliderInfinite || trg1.dataset.sliderInfinity) { if (rokna_onmouse.move_direction === undefined) { // ничего не делаем если нажали на точки (js-rokna-dot) } // если мы передвинем в лево, будет ближе? else if (Math.abs(slide_offsetLeft+slider_transformX+first_slide_offsetLeft) < Math.abs(slide_offsetLeft+slider_transformX)) { trg1.style.transition = ''; // отключим анимацию слайдера всю trg1.style.transform = 'translate3d('+(slider_transformX+first_slide_offsetLeft)+'px, 0px, 0px)'; slider_transformX = slider_transformX+first_slide_offsetLeft; // console.log('correct to left'); // увели в левую зону } // а если в право? else if (Math.abs(slide_offsetLeft+slider_transformX-first_slide_offsetLeft) < Math.abs(slide_offsetLeft+slider_transformX)) { trg1.style.transition = ''; // отключим анимацию слайдера всю trg1.style.transform = 'translate3d('+(slider_transformX-first_slide_offsetLeft)+'px, 0px, 0px)'; slider_transformX = slider_transformX-first_slide_offsetLeft; // console.log('correct to right'); // увели в правую зону, чтоб слайдер прокрутился влево } // тогда оставляем как есть else { // (пропуск) } } // сменяем текущий номер слайда trg1.dataset.selectedSlideNum = ev.slideNum; // новая позиция слайдера var stop_transformX = slide_offsetLeft * -1; // крайне правый слайд должен остаться прижатым к правому краю! var slider_wrapper_style = getComputedStyle(trg1.parentNode); var slider_wrapper_inner_width = trg1.parentNode.offsetWidth - parseInt(slider_wrapper_style.paddingRight) - parseInt(slider_wrapper_style.paddingLeft); // попросили учесть отрицательные отступы? var margins_param = trg1.dataset.sliderNegativeMargins || trg1.dataset.sliderMagins || trg1.dataset.sliderMargin || ''; if (!!margins_param && margins_param != 'ignore') { var slider_style = getComputedStyle(trg1); if (parseInt(slider_style.marginLeft) != 0) slider_wrapper_inner_width -= parseInt(slider_style.marginLeft); if (parseInt(slider_style.marginRight) != 0) slider_wrapper_inner_width -= parseInt(slider_style.marginRight); } var max_transformX = (trg1.scrollWidth - slider_wrapper_inner_width) * -1; // console.log('start='+start_transformX +' lastLeft='+ last_slide.offsetLeft +' lastWidth='+ last_slide.offsetWidth + ' wrap_width='+ slider_wrapper_inner_width +' max='+ max_transformX + ' scr_width='+trg1.scrollWidth); if (max_transformX > stop_transformX) stop_transformX = max_transformX; // мало слайдов -> прижимаем слева if (ev.slideNum == 0 && stop_transformX > 0) stop_transformX = 0; // останавливаем для начала анимацию предыдущую (если есть) rokna_onmouse({type: 'slider-stop-animate', targent: trg1}); // console.log('[slider-select]', ev.slideNum, last_slide, max_transformX, stop_transformX); // прокрутим rokna_onmouse({ type: 'slider-animate', target: trg1, start: slider_transformX, stop: stop_transformX, complete: function(){ // так-же обновим метку времени для autoplay slide.parentNode.dataset.autoplayTimestamp = (new Date())*1; } }); // обновим контролы rokna_onmouse({ type: 'slider-refresh-controls', target: trg1, slideNum: ev.slideNum }); } // [slider-infinite-initialize] if ( ev.type == 'slider-infinite-initialize' ) { var slider = trg1; // клонируем слева и справа слайды if(!slider.dataset.slideCount) { var first_original_slide; var slide_count = slider.dataset.slideCount = slider.children.length; // append for (var i=0; i= 0) { // console.info('rokna_onscroll', rec); // запустим обработчик var rec_callback_result = rec[0].call(block, ev, block_position); // если одноразовый, то удалим его if (rec_callback_result !== 'keep') { block.dataset.showed = true; if (i < rokna_onscroll.onprevisible_list.length) rokna_onscroll.onprevisible_list[i] = undefined; else rokna_onscroll_blocks[i-rokna_onscroll.onprevisible_list.length] = undefined; } } // else console.info('rokna_onscroll', rec[1].id||rec[1].className, block_position.top, window_innerHeight); } } catch(ex){ console.error(ex.stack); } } // список блоков для подгрузки rokna_onscroll.onprevisible_list = []; // старый список 'rokna_onscroll_blocks' in window ? null : (window.rokna_onscroll_blocks = []); // новый список // Test via a getter in the options object to see if the passive property is accessed var supportsPassive = false; try { var opts = Object.defineProperty({}, 'passive', { get: function() { supportsPassive = true; } }); window.addEventListener("testPassive", null, opts); window.removeEventListener("testPassive", null, opts); } catch (ex) {} window.addEventListener('scroll', rokna_onscroll, supportsPassive ? { passive: true } : false); // запустим скролл на DOMContentLoaded document.addEventListener("DOMContentLoaded", function(){ rokna_onscroll(); });