PageSourceSearch

https://visittyumen.ru/local/components/mendeleev/main.slider/templates/.default/MainSlider.js

js visittyumen.ru collected 2026-10-02 06:50:15 UTC 16,583 bytes, 425 lines download raw bytes

1class MainSlider{
2    MIN_SHIFT = 0;
3    isPaused = false;
4    TRANSITION = 1200;
5    QUICK_TRANSITION = 100;
6    TIME_QUICK_TRANSITION = 200;
7    MIN_SHIFT_PHONE = 20;
8    TRANSITION_PHONE = 300;
9    SCREEN_SIZE_PHONE = 576;
10    FIRST_SLIDE = 0;
11    VISIBLE_SLIDE = 1;
12    PLAY_VIDEO = true;
13    DELAY_STATE_CHANGE = 10;
14    $storage;
15    $slides;
16    $slide;
17    prevIndex;
18    index;
19    nextIndex
20    slideIndex;
21    slideSize;
22    slidesOffsetLeftBegin;
23    shiftStartX;
24    shiftEndX;
25    shiftStartY;
26    shiftEndY;
27    slidesOffsetLeft;
28    $dot;
29    PlayerState;
30    YT;
31    timerId;
32    widthLineBetweenDots;
33    videoId;
34    shiftTime = 0;
35    storageTransition;
36    autoplayParam = "Y";
37    speedParam = 15000;
38
39    constructor(storage, slides, dot, autoplay, speed){
40        this.$storage = $(storage);
41        this.$slides = $(slides);
42        this.$dot = $(dot);
43        this.$dots = $(dot).parent();
44        this.autoplayParam = autoplay;
45        this.speedParam = speed;
46        this.$document = $(document);
47        this.$window = $(window);
48        this.isFirstRender = true;
49        this.renderTimerId = null;
50        this.run();
51    }
52
53    init(){
54        this.index = this.FIRST_SLIDE;
55        this.checkIndex();
56        this.render(this.prevIndex, this.index, this.nextIndex);
57        this.slideSize = this.$slides.find(".js-main-slide-item").width();
58        this.slidesOffsetLeftBegin = this.$slides.offset().left;
59    }
60    syncSlidesHeight(){
61        let height = 0;
62        this.$storage.each((_, oItem) => {
63            height = Math.max(height, $(oItem).outerHeight());
64        });
65        this.$slides.css("min-height", height).children().css("min-height", height);
66    }
67    autoplay(){
68        if(this.autoplayParam !== "Y") return false;
69        this.timerId = setInterval(() => {
70            if(!this.isPaused){
71                let index = ++this.index;
72                this.checkDirection("right", index);
73            }
74        }, this.speedParam);
75    }
76    slideProgressBar(){
77        const progressBar = $(".main-slider__dots-controls-progress path"),
78            totalLength = progressBar[0].getTotalLength(),
79            animationDuration = this.speedParam,
80            startTime = performance.now();
81
82        function updateProgressBar(timestamp) {
83            const elapsedTime = timestamp - startTime,
84            progress = elapsedTime / animationDuration,
85            offset = totalLength * (1 - progress);
86            progressBar.css("strokeDashoffset", offset);
87
88            if(elapsedTime < animationDuration){
89                requestAnimationFrame(updateProgressBar);
90            }
91        }
92        requestAnimationFrame(updateProgressBar);
93    }
94    togglePause(){
95        this.isPaused = !this.isPaused;
96        clearTimeout(this.timerId);
97        if(!this.isPaused){
98            this.autoplay();
99            $('.main-slider__dots-controls').html('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">\n' +
100                '  <path d="M3 2.85714C3 2.38376 3.38376 2 3.85714 2H5.14286C5.61624 2 6 2.38376 6 2.85714V13.1429C6 13.6162 5.61624 14 5.14286 14H3.85714C3.38376 14 3 13.6162 3 13.1429V2.85714Z" fill="white"/>\n' +
101                '  <path d="M10 2.85714C10 2.38376 10.3838 2 10.8571 2H12.1429C12.6162 2 13 2.38376 13 2.85714V13.1429C13 13.6162 12.6162 14 12.1429 14H10.8571C10.3838 14 10 13.6162 10 13.1429V2.85714Z" fill="white"/>\n' +
102                '</svg>'+
103                '<svg class="main-slider__dots-controls-progress" viewBox="0 0 100 100" style="display: block; width: 100%;">' +
104                '   <path d="M 50,50 m 0,-46 a 46,46 0 1 1 0,92 a 46,46 0 1 1 0,-92" stroke="#fff" stroke-width="8" fill-opacity="0" style="stroke-dasharray: 289.067, 289.067; stroke-dashoffset: 289";>' +
105                '   </path>' +
106                '</svg>');
107            this.slideProgressBar();
108        }else{
109            $('.main-slider__dots-controls').html('<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">\n' +
110                '<path d="M14.0111 6.96962C14.7963 7.42757 14.7963 8.57243 14.0111 9.03038L5.76667 13.8388C4.98148 14.2968 4 13.7243 4 12.8084L4 3.19156C4 2.27566 4.98148 1.70323 5.76667 2.16118L14.0111 6.96962Z" fill="white"/>\n' +
111                '</svg>' +
112                '<svg class="main-slider__dots-controls-progress" viewBox="0 0 100 100" style="display: block; width: 100%;">' +
113                '   <path d="M 50,50 m 0,-46 a 46,46 0 1 1 0,92 a 46,46 0 1 1 0,-92" stroke="#fff" stroke-width="8" fill-opacity="0" style="stroke-dasharray: 289.067, 289.067; stroke-dashoffset: 289;">' +
114                '   </path>' +
115                '</svg>');
116        }
117    }
118    resetAutoplay(){
119        clearTimeout(this.timerId);
120        this.autoplay();
121    }
122
123    checkDirection(direction, nextIndex = null, event = ""){
124        this.finalizeTransition();
125        $(".js-main-slider-item-player iframe").hide();
126        if(typeof nextIndex === "number" && event === "click"){
127            this.render(this.prevIndex, this.index, nextIndex);
128            this.index = nextIndex;
129        }else if(typeof nextIndex === "number"){
130            this.index = nextIndex;
131        }else{
132            this.index = direction === "right" ? this.index += 1 : this.index -= 1;
133        }
134        if(nextIndex === this.slideIndex) return false;
135        this.checkIndex();
136        this.shiftAnimated(direction);
137        this.renderTimerId = setTimeout(() => {
138            this.renderTimerId = null;
139            this.render(this.prevIndex, this.index, this.nextIndex);
140        }, this.TRANSITION);
141    }
142
143    finalizeTransition(){
144        if(!this.renderTimerId) return;
145        clearTimeout(this.renderTimerId);
146        this.renderTimerId = null;
147        this.render(this.prevIndex, this.index, this.nextIndex);
148    }
149
150    render(){
151        this.$slides.html("");
152        for (let index = 0; index < arguments.length; index++){
153            const $slide = $(this.$storage[arguments[index]]).clone();
154            // Если это не первый рендер и слайд активный, отключаем lazyload для активного слайда
155            if(!this.isFirstRender && index === this.VISIBLE_SLIDE){
156                $slide.find("img.lazy-load").each((_, img) => {
157                    img.src = img.dataset.src;
158                    img.classList.remove("lazy-load");
159                });
160            }
161            this.$slides.append($slide);
162        }
163        this.syncSlidesHeight();
164        this.shift();
165        this.$slide = $(this.$slides.find(".js-main-slide-item")[this.VISIBLE_SLIDE]);
166        this.videoId = this.$slide.data("video-id");
167        this.$video = this.$slide.find(".main-slider__item--player")
168        this.videoType = this.$video.data("type")
169        this.slideIndex = this.$slide.data("index");
170        if(this.$window.width() > this.SCREEN_SIZE_PHONE){
171            this.setVideo();
172        }
173        this.setDot();
174
175        // После первого рендера устанавливаем флаг в false
176        if(this.isFirstRender){
177            this.isFirstRender = false;
178        }
179    }
180
181    shift(shift = 0){
182        this.$slides.css({
183            "transform": `translateX(${shift}px)`,
184            "transition": "0ms"
185        });
186    }
187
188    shiftAnimated(direction = "right"){
189        if(!this.isPaused){
190            this.slideProgressBar();
191        }
192        this.$slides.css({
193            "transform": `translateX(${direction === "right" ? -this.slideSize : this.slideSize}px)`,
194            "transition": `${this.TRANSITION}ms`
195        });
196    }
197
198    setVideo(){
199        if (this.videoType === 'youtube') {
200            this.$video.append(`<div id="player"></div>`);
201            if(this.PLAY_VIDEO === true && typeof this.videoId !== "undefined"){
202                new YT.Player("player", {
203                    videoId: this.videoId,
204                    playerVars: {
205                        playlist: this.videoId,
206                        autoplay: 1,
207                        controls: 0,
208                        mute: 1,
209                        loop: 1
210                    },
211                    events: {
212                        "onReady": this.onPlayerReady,
213                        "onStateChange": this.onPlayerStateChange
214                    }
215                });
216            }
217        }
218        if (this.videoType === 'rutube') {
219            let oVideo = new InitVideoRUTUBE(this.videoId)
220            oVideo.init()
221            this.$video.html(oVideo.htmlFrame)
222            this.$video.find("iframe").on('load', function () {
223                $(this)[0].contentWindow.postMessage(JSON.stringify({type: 'player:play', data: {}}), '*')
224                $(this)[0].contentWindow.postMessage(JSON.stringify({type: 'player:mute', data: {}}), '*')
225            })
226            this.onPlayerReady()
227            this.$video.find("iframe").fadeIn(800)
228        }
229    }
230
231    onPlayerReady = (e = null) => {
232        let slideWidth = this.$slide.width(),
233            slideHeight = this.$slide.height(),
234            slideHeightCalculated = slideWidth / 1.78;
235        if (this.videoType === 'youtube') {
236            let  player = e.target
237            player.playVideo();
238            player.setPlaybackQuality("highres");
239        }
240        if(slideHeightCalculated > slideHeight){
241            this.$video.find("iframe").css({
242                "width": slideWidth,
243                "height": slideHeightCalculated,
244                "top": `-${slideHeightCalculated / 2 - slideHeight / 2}px`,
245                "left": '0'
246            });
247        }else{
248            let slideWidthCalculated = slideHeight * 1.78;
249            this.$video.find("iframe").css({
250                "width": slideWidthCalculated,
251                "height": slideHeight,
252                "top": "0",
253                "left": `-${slideWidthCalculated / 2 - slideWidth / 2}px`
254            });
255        }
256    }
257
258    onPlayerStateChange = () => {
259        this.$video.find("iframe").fadeIn(800);
260    }
261
262    setDot(){
263        this.$dot.each((index, item) => {
264            const $item = $(item),
265                $svg = $item.find("svg"),
266                iDotsCount = this.$dot.length,
267                width = (this.$dots.width() - this.$dot.width() * iDotsCount) / (iDotsCount > 1 ? iDotsCount - 1 : 1);
268            if(width < 0) return false;
269            $svg.remove();
270            if(index === this.slideIndex){
271                $item.append(`
272                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
273                        <circle cx="10" cy="10" r="5" fill="#E86A4D"/>
274                        <circle cx="10" cy="10" r="4.5" stroke="white" stroke-opacity="0.3"/>
275                        <circle cx="10" cy="10" r="9.5" stroke="white"/>
276                     </svg>
277                `);
278            }else{
279                $item.append(`
280                   <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
281                       <circle opacity="0.7" cx="10" cy="10" r="5" fill="white"/>
282                       <circle cx="10" cy="10" r="4.5" stroke="white"/>
283                   </svg>  
284                `);
285            }
286        });
287    }
288
289    checkIndex(){
290        if(this.index < 0){
291            this.index = this.$storage.length - 1;
292        }else if(this.index > this.$storage.length - 1){
293            this.index = this.FIRST_SLIDE;
294        }
295        if(this.index === 0){
296            this.prevIndex = this.$storage.length - 1;
297            this.nextIndex = this.index + 1;
298        }else if(this.index === this.$storage.length - 1){
299            this.prevIndex = this.index - 1;
300            this.nextIndex = this.FIRST_SLIDE;
301        }else{
302            this.prevIndex = this.index - 1;
303            this.nextIndex = this.index + 1;
304        }
305    }
306
307    checkShiftTime(){
308        if(this.shiftTime + this.TRANSITION > $.now()){
309            this.storageTransition = this.TRANSITION;
310            this.TRANSITION = this.QUICK_TRANSITION;
311            this.shiftTime = $.now();
312            setTimeout(() => {
313                this.TRANSITION = this.storageTransition;
314            }, this.TIME_QUICK_TRANSITION);
315        }
316    }
317    nextSlide(){
318        if(this.isSliderVisible()){
319            this.resetAutoplay();
320            this.checkDirection("right");
321        }
322    }
323    prevSlide(){
324        if(this.isSliderVisible()) {
325            this.resetAutoplay();
326            this.checkDirection("left");
327        }
328    }
329    handleKeyPress(event){
330        if(event.key === "ArrowRight"){
331            this.nextSlide();
332        }else if(event.key === "ArrowLeft"){
333            this.prevSlide();
334        }
335    }
336    isSliderVisible(){
337        let sliderRect = this.$slides[0].getBoundingClientRect(),
338            isVisible = (sliderRect.top < window.innerHeight && sliderRect.bottom >= 0) &&
339            (sliderRect.left < window.innerWidth && sliderRect.right >= 0);
340        return isVisible;
341    }
342    run(){
343        if(this.$window.width() < this.SCREEN_SIZE_PHONE){
344            this.TRANSITION = this.TRANSITION_PHONE;
345            this.MIN_SHIFT = this.MIN_SHIFT_PHONE;
346        }
347        $(document).keydown((event) => {
348            this.handleKeyPress(event);
349        });
350        this.init();
351        this.autoplay();
352        if(!this.isPaused){
353            this.slideProgressBar();
354        }
355        this.$dot.on("click", (e) => {
356            e = e.originalEvent;
357            if(e) e.stopPropagation();
358            this.resetAutoplay();
359            let index = $(e.target).closest(".js-main-dot").index() - 1,
360                direction = this.index > index ? "left" : "right";
361            this.checkDirection(direction, index, "click");
362        });
363        this.$window.on("resize.mainSlider", () => {
364            this.syncSlidesHeight();
365            this.slideSize = this.$slides.find(".js-main-slide-item").width();
366        });
367        this.$slides.on("mousedown touchstart", (e) => {
368            e = e.originalEvent;
369            if(e) e.stopPropagation();
370            this.resetAutoplay();
371            this.checkShiftTime();
372            this.finalizeTransition();
373            if(e.type === "touchstart"){
374                this.shiftStartX = e.targetTouches[0].clientX;
375                this.shiftStartY = e.targetTouches[0].clientY;
376            }else{
377                this.shiftStartX = e.clientX;
378                this.shiftStartY = e.clientY;
379            }
380            this.shiftEndX = this.shiftStartX;
381            this.shiftEndY = this.shiftStartY;
382            this.slidesOffsetLeft = this.$slides.offset().left;
383            this.$slides.on("mousemove touchmove", (e) => {
384                e = e.originalEvent;
385                if(e) e.stopPropagation();
386                if(this.$window.width() <= this.SCREEN_SIZE_PHONE){
387                    if(Math.abs(this.shiftEndY - this.shiftStartY) > Math.abs(this.shiftEndX - this.shiftStartX)) this.$slides.off("mousemove touchmove");
388                }
389                if(e.type === "touchmove"){
390                    this.shiftStartX = e.targetTouches[0].clientX;
391                    this.shiftStartY = e.targetTouches[0].clientY;
392                }else{
393                    this.shiftStartX = e.clientX;
394                    this.shiftStartY = e.clientY;
395                }
396                let shiftValue = this.slidesOffsetLeft - (this.shiftEndX - this.shiftStartX) - this.slidesOffsetLeftBegin;
397                shiftValue = Math.max(-this.slideSize, Math.min(this.slideSize, shiftValue));
398                this.shift(shiftValue);
399            });
400        });
401        this.$slides.on("mouseup touchend", (e) => {
402            e = e.originalEvent;
403            if(e) e.stopPropagation();
404            this.shiftTime = $.now();
405            this.$slides.off("mousemove touchmove");
406            let diff = this.shiftEndX - this.shiftStartX;
407            if(Math.abs(diff) < this.MIN_SHIFT){
408                this.$slides.css({
409                    "transform": `translateX(${this.slidesOffsetLeft - this.slidesOffsetLeftBegin}px)`,
410                    "transition": `${this.TRANSITION}ms`
411                });
412            }else if(diff > 0){
413                this.checkDirection("right");
414            }else if(diff < 0){
415                this.checkDirection("left");
416            }
417        });
418        $(".main-slider__dots-controls").on("click", () => {
419            this.togglePause();
420        });
421        window.onYouTubeIframeAPIReady = () => {
422            this.PLAY_VIDEO = true;
423        }
424    }
425}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.