PageSourceSearch

https://visitmadison.org/wp-content/plugins/swift-framework/includes/swift-slider/assets/js/swift-slider.js

js visitmadison.org collected 2026-10-02 10:09:40 UTC 168,613 bytes, 3,989 lines download raw bytes

1/*global jQuery, SWIFT, WheelEvent */
2/*jshint unused:false*/
3
4/*
5 *
6 *  Swift Slider Frontend JS
7 *  ------------------------------------------------
8 *  Swift Slider
9 *  Copyright Swift Ideas 2016 - http://www.swiftideas.com
10 *
11 */
12
13var SWIFTSLIDER = SWIFTSLIDER || {};
14
15(function() {
16
17    // USE STRICT
18    "use strict";
19
20    var swiftSliderElements = [],
21        $window = jQuery( window ),
22        body = jQuery( 'body' ),
23        deviceAgent = navigator.userAgent.toLowerCase(),
24        isMobile = deviceAgent.match( /(iphone|ipod|android|iemobile)/ ),
25        isMobileAlt = deviceAgent.match( /(iphone|ipod|ipad|android|iemobile)/ ),
26        isAppleDevice = deviceAgent.match( /(iphone|ipod|ipad)/ ),
27        isAndroid = deviceAgent.indexOf("android") > -1,
28        isSafari = navigator.userAgent.search("Safari") >= 0 && navigator.userAgent.search("Chrome") < 0,
29        parallaxCanScroll = navigator.userAgent.indexOf( 'Safari' ) != -1 || navigator.userAgent.indexOf( 'Chrome' ) == -1,
30        parallaxInstance = null,
31        parallaxSliderHeight = 0,
32        scrollLimited = false;
33
34    SWIFTSLIDER.curtainAnimating = false;
35
36    SWIFTSLIDER = {
37        init: function() {
38
39            // Set up each slider
40            jQuery( '.swift-slider' ).each(
41                function( i ) {
42
43                    var ssInstance = jQuery( this ),
44                        sliderID = ssInstance.attr( 'id' ),
45                        ssFullscreen = ssInstance.data( 'fullscreen' ),
46                        windowHeight = parseInt( $window.height(), 10 ),
47                        ssMaxHeight = parseInt( ssInstance.data( 'max-height' ), 10 );
48
49                    // Skip if no slides found
50                    if ( ssInstance.hasClass( 'no-slides' ) ) {
51                        return false;
52                    }
53
54                    // Set the slider height
55                    if ( jQuery( '#wpadminbar' ).length > 0 ) {
56                        windowHeight = windowHeight - jQuery( '#wpadminbar' ).height();
57                    }
58
59                    var sliderHeight = windowHeight > ssMaxHeight || !ssFullscreen && ssMaxHeight ? ssMaxHeight : windowHeight;
60
61                    if ( jQuery( '#top-bar' ).length > 0 ) {
62                        sliderHeight = sliderHeight - jQuery( '#top-bar' ).height();
63                    }
64
65                    ssInstance.css( 'height', sliderHeight );
66
67                    // Setup slider
68                    SWIFTSLIDER.setupSlider( i, sliderID );
69
70                    // Prepare the first slide
71                    SWIFTSLIDER.prepareFirstSlide( i, jQuery( '#' + sliderID ) );
72                }
73            );
74
75            $window.on("throttledresize", function() {
76                setTimeout(function() {
77                    SWIFTSLIDER.resizeSliders();
78                }, 100);
79            });
80
81        },
82        setupSlider: function( i, sliderID ) {
83
84            // Slider variables
85            var sliderInstance = '#' + sliderID,
86                sliderElement = jQuery( sliderInstance ),
87                sliderType = sliderElement.data( 'slider-type' ),
88                sliderAuto = parseInt( sliderElement.data( 'autoplay' ), 10 ),
89                sliderTransition = sliderElement.data( 'transition' ),
90                sliderLoop = sliderElement.data( 'loop' ),
91                slideCount = sliderElement.data( 'slide-count' ),
92                mobileNoSwipe = false,
93                desktopSwipe = true,
94                grabAbility = true;
95
96            if ( slideCount === 1 ) {
97                desktopSwipe = false;
98                grabAbility = false;
99                mobileNoSwipe = true;
100            }
101
102            // Set up the Swift Slider instance
103            if ( sliderType == "curtain" ) {
104                swiftSliderElements[i] = new SwiftSwiper(
105                    sliderInstance, {
106                        loop: false,
107                        progress: true,
108                        mode: 'vertical',
109                        transition: "slide",
110                        speed: 1000,
111                        autoplay: sliderAuto,
112                        keyboardControl: true,
113                        simulateTouch: false,
114                        mousewheelControl: true,
115                        mousewheelControlForceToAxis: true,
116                        noSwiping: mobileNoSwipe,
117                        onFirstInit: SWIFTSLIDER.afterSliderCurtainInit,
118                        onSlideChangeStart: SWIFTSLIDER.slideTransitionStart,
119                        onSlideChangeEnd: SWIFTSLIDER.slideTransitionEnd,
120                        onTouchStart: function( swiper ) {
121                            for ( var i = 0; i < swiper.slides.length; i++ ) {
122                                swiper.setTransition( swiper.slides[i], 0 );
123                            }
124                        },
125                        onSetWrapperTransition: function( swiper, speed ) {
126                            for ( var i = 0; i < swiper.slides.length; i++ ) {
127                                swiper.setTransition( swiper.slides[i], speed );
128                            }
129                        }
130                    }
131                );
132            } else if ( sliderType == "slider" && sliderTransition == "fade" ) {
133                swiftSliderElements[i] = new SwiftSwiper(
134                    sliderInstance, {
135                        loop: sliderLoop,
136                        progress: true,
137                        touchRatio: 0.7,
138                        speed: 1200,
139                        transition: "fade",
140                        autoplay: sliderAuto,
141                        grabCursor: grabAbility,
142                        paginationClickable: true,
143                        keyboardControl: true,
144                        noSwiping: mobileNoSwipe,
145                        simulateTouch: desktopSwipe,
146                        onFirstInit: SWIFTSLIDER.afterSliderInit,
147                        onSlideChangeStart: SWIFTSLIDER.slideTransitionStart,
148                        onSlideChangeEnd: SWIFTSLIDER.slideTransitionEnd,
149                        onProgressChange: function(swiper) {
150                            for (var i = 0; i < swiper.slides.length; i++) {
151                                var slide = swiper.slides[i];
152                                var progress = slide.progress;
153                                var translate = progress*swiper.width;
154                                //var opacity = 1 - Math.min(Math.abs(progress),1);
155                                //slide.style.opacity = opacity;
156                                swiper.setTransform(slide,'translate3d('+translate+'px,0,0)');
157                            }
158                        },
159                        onTouchStart:function(swiper){
160                            for (var i = 0; i < swiper.slides.length; i++) {
161                                swiper.setTransition(swiper.slides[i], 0);
162                            }
163                        },
164                        onSetWrapperTransition: function(swiper, speed) {
165                            for (var i = 0; i < swiper.slides.length; i++) {
166                                swiper.setTransition(swiper.slides[i], speed);
167                            }
168                        }
169                    }
170                );
171            } else {
172                swiftSliderElements[i] = new SwiftSwiper(
173                    sliderInstance, {
174                        loop: sliderLoop,
175                        touchRatio: 0.7,
176                        mode: 'horizontal',
177                        transition: "slide",
178                        speed: 600,
179                        autoplay: sliderAuto,
180                        grabCursor: grabAbility,
181                        paginationClickable: true,
182                        keyboardControl: true,
183                        noSwiping: mobileNoSwipe,
184                        simulateTouch: desktopSwipe,
185                        onFirstInit: SWIFTSLIDER.afterSliderInit,
186                        onSlideChangeStart: SWIFTSLIDER.slideTransitionStart,
187                        onSlideChangeEnd: SWIFTSLIDER.slideTransitionEnd
188                    }
189                );
190
191                if ( mobileNoSwipe ) {
192                    sliderElement.addClass( 'no-swiping' );
193                }
194            }
195
196            // Resize the sliders
197            swiftSliderElements[i].resizeFix();
198
199        },
200        prepareFirstSlide: function( i, sliderInstance ) {
201
202            var delay = 600;
203
204            // Set controls style based on the slide
205            sliderInstance.find( '.swift-slider-pagination, .swift-slider-prev, .swift-slider-next, .swift-slider-continue' ).removeClass( 'dark' ).removeClass( 'light' ).addClass( sliderInstance.find( '.swiper-slide-active' ).data( 'style' ) );
206
207            // Check if first slide has a video
208            if ( sliderInstance.find( '.swiper-slide-active video' ).length > 0 ) {
209                // Check if browser supports video
210                jQuery.canVideoautoplay(function ( canAutoplay ) {
211
212                    if (canAutoplay || isAndroid) {
213                        // Get video instance
214                        var videoElement = sliderInstance.find( '.swiper-slide-active video' ).first(),
215                            videoInstance = videoElement.get( 0 );
216                        
217                        if (typeof videoInstance === 'undefined') {
218                            return;
219                        }
220
221                        // Load video
222                        videoInstance.load();
223
224                        // Add event listener for when video has loaded
225                        videoInstance.addEventListener(
226                            'loadeddata', function() {
227                                // Slide video loaded, now display the slider
228                                SWIFTSLIDER.sliderLoaded( i, sliderInstance );
229                                SWIFTSLIDER.setSliderContent( sliderInstance );
230                                SWIFTSLIDER.showControls( sliderInstance );
231                                SWIFTSLIDER.slideTransitionEnd( swiftSliderElements[i], delay );
232
233                            }
234                        );
235
236                        // Add function to video end when no loop used
237                        videoInstance.onended = function(e) {
238                            if ( !videoElement.attr('loop') ) {
239                                sliderInstance.find( '.swiper-slide-active video' ).addClass('finished');
240                            }
241                        };
242
243                    } else {
244
245                        // Video not supported, remove video and continue loading slider
246                        sliderInstance.find( '.swiper-slide-active video' ).remove();
247                        SWIFTSLIDER.sliderLoaded( i, sliderInstance );
248                        SWIFTSLIDER.setSliderContent( sliderInstance );
249                        SWIFTSLIDER.showControls( sliderInstance );
250                        SWIFTSLIDER.slideTransitionEnd( swiftSliderElements[i], delay );
251                    }
252                });
253            } else {
254                var slideImageURL = sliderInstance.find( '.swiper-slide-active' ).data( 'slide-img' );
255                if ( slideImageURL && slideImageURL.length > 0 ) {
256
257                    var slideImage = new Image();
258
259                    // Callback for when slideImage loads
260                    jQuery( slideImage ).load(
261                        function() {
262
263                            // Slide image loaded, now display the slider
264                            SWIFTSLIDER.sliderLoaded( i, sliderInstance );
265                            SWIFTSLIDER.setSliderContent( sliderInstance );
266                            SWIFTSLIDER.showControls( sliderInstance );
267                            SWIFTSLIDER.slideTransitionEnd( swiftSliderElements[i], delay );
268                        }
269                    );
270
271                    // Set the source
272                    slideImage.src = slideImageURL;
273
274                } else {
275
276                    // If all else fails, now display the slider
277                    SWIFTSLIDER.sliderLoaded( i, sliderInstance );
278                    SWIFTSLIDER.setSliderContent( sliderInstance );
279                    SWIFTSLIDER.showControls( sliderInstance );
280                    SWIFTSLIDER.slideTransitionEnd( swiftSliderElements[i], delay );
281                }
282
283            }
284
285        },
286        afterSliderInit: function(e) {
287
288            // Resize the sliders
289            SWIFTSLIDER.resizeSliders();
290
291            // Pause video if slider goes off screen
292            $window.scroll(
293                function() {
294                    jQuery( '.swift-slider' ).each(
295                        function() {
296                            var ssInstance = jQuery( this ),
297                                visibleSlide = ssInstance.find('.swiper-slide-active'),
298                                slideVideo = visibleSlide.find('video');
299
300                            if (slideVideo.length > 0) {
301
302                                if ( ssInstance.is(':in-viewport') && !slideVideo.hasClass('finished') ) {
303                                    if (slideVideo.parents('.swiper-slide-active').length > 0) {
304                                        slideVideo.get( 0 ).play();
305                                    }
306                                } else {
307                                    slideVideo.each(function() {
308                                        jQuery(this).get( 0 ).pause();
309                                    });
310                                }
311
312                            }
313
314                        }
315                    );
316                }
317            );
318
319        },
320        afterSliderCurtainInit: function( e ) {
321
322            var sliderObject = e,
323                sliderInstance = jQuery( sliderObject.container ),
324                scrollIndicator = sliderInstance.find( '.swift-scroll-indicator' );
325
326            // Resize the sliders
327            SWIFTSLIDER.resizeSliders();
328
329            // Scroll Indicator Animate
330            setTimeout(
331                function() {
332                    SWIFTSLIDER.scrollIndicatorAnimate( scrollIndicator );
333                }, 1000
334            );
335
336            // Bind scroll event on load
337            if ( $window.scrollTop() < 10 ) {
338                SWIFTSLIDER.curtainEnter( sliderObject, sliderInstance );
339            } else {
340                jQuery( 'body,html' ).animate(
341                    {
342                        scrollTop: sliderInstance.scrollTop()
343                    }, 200, 'easeOutCubic', function() {
344                        SWIFTSLIDER.curtainEnter( sliderObject, sliderInstance );
345                    }
346                );
347
348            }
349
350            // Check when slider is hovered & bind mousewheel
351            sliderInstance.on(
352                'mouseenter', function() {
353                    //body.css( 'overflow', 'hidden' );
354                    SWIFTSLIDER.curtainEnter( sliderObject, sliderInstance );
355                }
356            );
357
358            // Remove
359            sliderInstance.on(
360                'mouseleave', function() {
361                    //body.css( 'overflow', '' );
362                }
363            );
364
365        },
366        scrollIndicatorAnimate: function( scrollIndicator ) {
367
368            var timer = false,
369                indicatorDots = scrollIndicator.find( 'span' );
370
371            if ( scrollIndicator.hasClass( 'indicator-hidden' ) ) {
372                return false;
373            }
374
375            indicatorDots.each(
376                function( n, i ) {
377                    i = jQuery( i );
378
379                    i.delay( n * 100 ).animate(
380                        {
381                            opacity: 1
382                        }, 100, function() {
383                            i.animate(
384                                {
385                                    opacity: 0
386                                }, 500, function() {
387                                    if ( n === indicatorDots.length - 1 ) {
388                                        timer = setTimeout(
389                                            function() {
390                                                SWIFTSLIDER.scrollIndicatorAnimate( scrollIndicator );
391                                            }, 2000
392                                        );
393                                    }
394                                }
395                            );
396                        }
397                    );
398                }
399            );
400        },
401        curtainEnter: function( sliderObject, sliderInstance ) {
402            var isScrolling = false;
403            if ( typeof SWIFT != 'undefined' ) {
404                isScrolling = SWIFT.isScrolling;
405            }
406            if ( $window.scrollTop() > 0 && !isScrolling ) {
407                jQuery( 'body,html' ).animate(
408                    {
409                        scrollTop: sliderInstance.scrollTop()
410                    }, 800, 'easeOutCubic', function() {
411                        SWIFTSLIDER.curtainAnimating = false;
412                    }
413                );
414            }
415            if ( !sliderInstance.data( 'continue' ) ) {
416                SWIFTSLIDER.curtainAnimating = false;
417            }
418        },
419        sliderLoaded: function( i, sliderInstance ) {
420
421            // Fade out the loader
422            sliderInstance.find( '#swift-slider-loader' ).fadeOut( 400 );
423
424            // Fade in the slider
425            sliderInstance.find( '.swiper-wrapper' ).animate(
426                {
427                    'opacity': 1
428                }, 400
429            );
430
431            // Fade in the video overlays
432            sliderInstance.find( '.video-overlay' ).animate(
433                {
434                    'opacity': 1
435                }, 400
436            );
437
438            // Initiate parallax scrolling on the slider if it's using the hero location
439            if ( (sliderInstance.parent().parent( '#container' ).length > 0 || sliderInstance.parent().parent( 'body' ).length > 0 || sliderInstance.offset().top === 0) && !body.hasClass('header-standard') && !body.hasClass('layout-boxed') && sliderInstance.data( 'slider-type' ) != "curtain" && !isMobileAlt && !body.hasClass('ss-parallax-disabled') && !body.hasClass('post-type-archive-product') ) {
440                sliderInstance.addClass('swift-slider-parallax');
441                parallaxInstance = sliderInstance;
442                SWIFTSLIDER.parallax();
443            }
444
445            // Slider prev button
446            sliderInstance.find( '.swift-slider-prev' ).on(
447                'click', function( e ) {
448                    e.preventDefault();
449                    if ( body.css( "direction" ).toLowerCase() == "rtl" ) {
450                        swiftSliderElements[i].swipeNext();
451                    } else {
452                        swiftSliderElements[i].swipePrev();
453                    }
454                }
455            );
456
457            // Slider next button
458            sliderInstance.find( '.swift-slider-next' ).on(
459                'click', function( e ) {
460                    e.preventDefault();
461                    if ( body.css( "direction" ).toLowerCase() == "rtl" ) {
462                        swiftSliderElements[i].swipePrev();
463                    } else {
464                        swiftSliderElements[i].swipeNext();
465                    }
466                }
467            );
468
469            // Slider pagination
470            sliderInstance.find( '.swift-slider-pagination' ).on(
471                'click', '> div', function( e ) {
472                    swiftSliderElements[i].swipeTo( jQuery( this ).index() );
473                    sliderInstance.find( '.swift-slider-pagination .dot' ).removeClass( 'active' );
474                    jQuery( this ).addClass( 'active' );
475                }
476            );
477
478            // Curtain slider continue
479            sliderInstance.find( '.swift-slider-continue' ).on(
480                'click', function( e ) {
481                    e.preventDefault();
482                    SWIFTSLIDER.curtainAdvance( sliderInstance );
483                }
484            );
485
486        },
487        curtainAdvance: function( sliderInstance ) {
488
489            if ( !sliderInstance.data( 'continue' ) ) {
490                return false;
491            }
492
493            var stickyHeaderHeight = body.hasClass( 'sticky-header-enabled' ) && !body.hasClass( 'header-below-slider' ) && jQuery( '.header-wrap' ).is( ':visible' ) ? jQuery( '.sticky-header' ).outerHeight() : 0;
494
495            if ( body.hasClass( 'mh-sticky' ) && jQuery( '#mobile-header' ).is( ':visible' ) ) {
496                stickyHeaderHeight = jQuery('#mobile-header').outerHeight();
497            }
498
499            if ( body.hasClass( 'sh-dynamic' ) && !jQuery( '.header-wrap' ).hasClass( 'full-header-stick' ) ) {
500                stickyHeaderHeight = stickyHeaderHeight - 20;
501            }
502
503            if ( jQuery('.sticky-top-bar').length > 0 && jQuery( '.sticky-top-bar' ).is( ':visible' ) ) {
504                stickyHeaderHeight = stickyHeaderHeight + jQuery('.sticky-top-bar').outerHeight();
505            }
506
507            var sliderScrollTop = sliderInstance.offset().top + sliderInstance.height() - stickyHeaderHeight;
508
509
510            if ( jQuery( '#wpadminbar' ).length > 0 ) {
511                sliderScrollTop = sliderScrollTop - jQuery( '#wpadminbar' ).height();
512            }
513
514            jQuery( 'body,html' ).stop( true, false ).animate(
515                {
516                    scrollTop: sliderScrollTop
517                }, 800
518            );
519
520            if ( !isMobileAlt ) {
521                body.css( 'overflow', '' );
522            }
523            // SWIFTSLIDER.curtainAnimating = true;
524        },
525        showControls: function( sliderInstance ) {
526
527            // Animate in controls
528            if ( sliderInstance.data( 'slider-type' ) != "curtain" ) {
529                if ( sliderInstance.data( 'loop' ) ) {
530                    sliderInstance.find( '.swift-slider-prev' ).fadeIn( 400 );
531                }
532                sliderInstance.find( '.swift-slider-next' ).fadeIn( 400 );
533                sliderInstance.find( '.swift-slider-pagination .dot' ).first().addClass( 'active' );
534                sliderInstance.find( '.swift-slider-pagination' ).fadeIn( 600 );
535                sliderInstance.find( '.swift-slider-continue' ).removeClass( 'continue-hidden' );
536            } else if ( sliderInstance.data( 'slider-type' ) === "curtain" ) {
537                sliderInstance.find( '.swift-slider-pagination .dot' ).first().addClass( 'active' );
538                sliderInstance.find( '.swift-slider-pagination' ).css(
539                    'margin-top', -sliderInstance.find( '.swift-slider-pagination' ).height() / 2
540                );
541                sliderInstance.find( '.swift-slider-pagination' ).fadeIn( 600 );
542                if ( sliderInstance.find( '.swiper-slide' ).length < 2 ) {
543                    sliderInstance.find( '.swift-slider-continue' ).removeClass( 'continue-hidden' );
544                }
545            }
546
547        },
548        parallax: function() {
549
550            parallaxSliderHeight = parallaxInstance.height();
551            $window.smartresize(
552                function() {
553                    parallaxSliderHeight = parallaxInstance.height();
554                }
555            );
556
557            window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function(f){ 
558                setTimeout(f, 1000/60);
559            };
560
561            if ( parallaxCanScroll ) {
562                window.addEventListener('scroll', function() { 
563                    requestAnimationFrame(SWIFTSLIDER.parallaxScroll);
564                }, false);
565            }
566        },
567        parallaxScroll: function(sliderHeight) {
568
569            var scrollTop = $window.scrollTop();
570
571            // Check if window width is greater than mobile sized
572            if ( $window.width() > 768 ) {
573
574                // Transition the slider wrapper
575                parallaxInstance.stop( true, true ).transition(
576                    {
577                        y: scrollTop * - 0.2
578                    }, 0
579                );
580
581                // Transition the caption
582                parallaxInstance.find( '.caption-wrap' ).stop( true, true ).transition(
583                    {
584                        y: scrollTop * - 0.15,
585                        opacity: 1 - scrollTop / ( parallaxSliderHeight - 150 )
586                    }, 0
587                );
588
589                // Fade the pagination
590                parallaxInstance.find( '.swift-slider-pagination' ).stop( true, true ).transition(
591                    {
592                        opacity: 1 - scrollTop / ( parallaxSliderHeight - 150 )
593                    }, 0
594                );
595            }
596
597            var parallaxWrap = parallaxInstance.parent();
598            var docViewBottom = scrollTop + $window.height();
599            var elemTop = parallaxWrap.offset().top;
600            var elemBottom = elemTop + parallaxWrap.height();
601            var stickyHeaderHeight = body.hasClass( 'sticky-header-enabled' ) && !body.hasClass( 'header-below-slider' ) && jQuery( '.header-wrap' ).is( ':visible' ) ? jQuery( '.sticky-header' ).outerHeight() : 0;
602
603
604            if ( scrollTop >= elemBottom - stickyHeaderHeight ) {
605                parallaxWrap.addClass('not-visible');
606            } else {
607                parallaxWrap.removeClass('not-visible');
608            }
609
610        },
611        resizeSliders: function( sliderInstance ) {
612
613            // Cache the windowHeight
614            var windowHeight = parseInt( $window.height(), 10 );
615
616            if ( jQuery( '#wpadminbar' ).length > 0 ) {
617                windowHeight = windowHeight - jQuery( '#wpadminbar' ).height();
618            }
619
620            // Resize each slider
621            if ( sliderInstance ) {
622
623                var ssInstance = sliderInstance,
624                    ssFullscreen = ssInstance.data( 'fullscreen' ),
625                    ssMaxHeight = parseInt( ssInstance.data( 'max-height' ), 10 ),
626                    ssVideoWrap = ssInstance.find( '.video-wrap' ),
627                    sliderHeight = windowHeight > ssMaxHeight && !ssFullscreen ? ssMaxHeight : windowHeight,
628                    sliderWidth = ssInstance.width();
629
630                // Set slider and slide width & height
631                SWIFTSLIDER.setSliderSize( ssInstance, ssFullscreen, sliderWidth, sliderHeight );
632
633                // Check if a video is present
634                if ( ssVideoWrap.length > 0 ) {
635                    SWIFTSLIDER.setSlideVideoSize( ssVideoWrap, sliderWidth, sliderHeight );
636                }
637
638            } else {
639
640                jQuery( '.swift-slider' ).each(
641                    function() {
642                        var ssInstance = jQuery( this ),
643                            ssFullscreen = ssInstance.data( 'fullscreen' ),
644                            ssMaxHeight = parseInt( ssInstance.data( 'max-height' ), 10 ),
645                            ssVideoWrap = ssInstance.find( '.video-wrap' ),
646                            sliderHeight = windowHeight > ssMaxHeight && !ssFullscreen ? ssMaxHeight : windowHeight,
647                            sliderWidth = ssInstance.width();
648                        
649                        // Set slider and slide width & height
650                        SWIFTSLIDER.setSliderSize( ssInstance, ssFullscreen, sliderWidth, sliderHeight );
651
652                        // Check if a video is present
653                        if ( ssVideoWrap.length > 0 ) {
654                            SWIFTSLIDER.setSlideVideoSize( ssVideoWrap, sliderWidth, sliderHeight );
655                        }
656                    }
657                );
658
659            }
660
661        },
662        setSliderSize: function( ssInstance, ssFullscreen, sliderWidth, sliderHeight ) {
663            // Modify height based on other elements
664            if ( !body.hasClass( 'vertical-header' ) && !body.hasClass( 'header-naked-light' ) && !body.hasClass( 'header-naked-dark' ) && !body.hasClass( 'header-standard-overlay' ) && ssFullscreen && jQuery( '.header-wrap' ).css('display') !== 'none' && !body.hasClass( 'header-below-slider' ) ) {
665                sliderHeight = sliderHeight - jQuery( '.header-wrap' ).height();
666            }
667
668            if ( body.hasClass( 'vertical-header' ) && jQuery( '#wpadminbar' ).length > 0 && ssFullscreen ) {
669                //sliderHeight = sliderHeight + jQuery('#wpadminbar').height();
670            }
671
672            if ( jQuery( '#mobile-top-text' ).is( ':visible' ) ) {
673                sliderHeight = sliderHeight - jQuery( '#mobile-top-text' ).height();
674            }
675
676            if ( jQuery( '#mobile-header' ).css('display') !== 'none' && !body.hasClass( 'header-below-slider' ) ) {
677                sliderHeight = sliderHeight - jQuery( '#mobile-header' ).outerHeight();
678            }
679
680            if ( jQuery( '#top-bar' ).length > 0 ) {
681                sliderHeight = sliderHeight - jQuery( '#top-bar' ).height();
682            }
683
684            if ( jQuery( '#sf-header-banner' ).length > 0 && !body.hasClass( 'header-below-slider' ) ) {
685                sliderHeight = sliderHeight - jQuery( '#sf-header-banner' ).height();
686            }
687
688            // Set slider height + width
689            ssInstance.css( 'height', sliderHeight );
690            ssInstance.parents('.swift-slider-outer').css( 'height', sliderHeight );
691            ssInstance.find( '.swiper-container, .swiper-slide' ).css( 'height', sliderHeight );
692            ssInstance.find( '.swiper-container' ).css( 'width', sliderWidth );
693
694            // Vertically center caption & fade in
695            var contentHeight = 0;
696            ssInstance.find( '.caption-content' ).each(
697                function() {
698                    var caption = jQuery( this ),
699                        captionHeight = jQuery( this ).height();
700
701                    if ( captionHeight > contentHeight ) {
702                        contentHeight = captionHeight;
703                    }
704
705                    caption.css( 'margin-top', -captionHeight / 2 );
706                }
707            );
708
709            // Increase slider height if content height is larger
710            if ( contentHeight > sliderHeight ) {
711                ssInstance.css( 'height', contentHeight + 60 );
712                ssInstance.parents('.swift-slider-outer').css( 'height', contentHeight + 60 );
713                ssInstance.find( '.swiper-container, .swiper-slide' ).css( 'height', contentHeight + 60 );
714            }
715        },
716        setSlideVideoSize: function( ssVideoWrap, sliderWidth, sliderHeight ) {
717            var ssVideo = ssVideoWrap.find( '.video' ),
718                videoWidth = parseInt( ssVideo.data( 'width' ), 10 ),
719                videoHeight = parseInt( ssVideo.data( 'height' ), 10 );
720
721            // Set video width/height if needed
722            if ( videoWidth === 0 ) {
723                videoWidth = ssVideo[0].videoWidth;
724            }
725            if ( videoHeight === 0 ) {
726                videoHeight = ssVideo[0].videoHeight;
727            }
728            // Last ditch fallbacks
729            if ( videoWidth === 0 ) {
730                videoWidth = 1920;
731            }
732            if ( videoHeight === 0 ) {
733                videoHeight = 1080;
734            }
735
736            // Set slide video width + height
737            ssVideo.css( 'height', sliderHeight ).css( 'width', sliderWidth );
738            ssVideoWrap.width( sliderWidth ).height( sliderHeight );
739
740            // Use the largest scale factor of horizontal/vertical
741            var scale_h = sliderWidth / videoWidth;
742            var scale_v = sliderHeight / videoHeight;
743            var scale = scale_h > scale_v ? scale_h : scale_v;
744
745            // Update minium width to never allow excess space
746            var min_w = videoWidth / videoHeight * (sliderHeight + 20);
747
748            // Don't allow scaled width < minimum video width
749            if ( scale * videoWidth < min_w ) {
750                scale = min_w / videoWidth;
751            }
752
753            // Scale the video
754            ssVideo.width( Math.ceil( scale * videoWidth + 2 ) );
755            ssVideo.height( Math.ceil( scale * videoHeight + 2 ) );
756
757            // Center the video wrap
758            ssVideo.css( 'margin-top', -(ssVideo.height() - ssVideoWrap.height()) / 2 );
759            ssVideo.css( 'margin-left', -(ssVideo.width() - ssVideoWrap.width()) / 2 );
760        },
761        slideTransitionStart: function( e ) {
762            var sliderObject = e,
763                sliderInstance = jQuery( sliderObject.container ),
764                currentSlide = jQuery( e.activeSlide() ),
765                currentSlideIndex = e.activeIndex,
766                currentSlideID = currentSlide.data( 'slide-id' ) ? parseInt( currentSlide.data( 'slide-id' ), 10 ) : 1,
767                pagination = sliderInstance.find( '.swift-slider-pagination' ),
768                numberOfSlides = pagination.find( '.dot' ).length,
769                ssContinue = sliderInstance.data( 'continue' );
770
771            if ( sliderInstance.is(':in-viewport') && ( body.hasClass('header-naked-light') || body.hasClass('header-naked-dark')) && $window.scrollTop() < 1 ) {
772                var slideColour = currentSlide.data('header-style');
773                jQuery('.header-wrap').attr('data-style', slideColour);
774            }
775
776            // Resize current slider
777            //SWIFTSLIDER.resizeSliders( sliderInstance );
778
779            // Update pagination
780            if ( sliderInstance.data( 'slider-type' ) === "curtain" ) {
781                currentSlideIndex = currentSlideIndex + 1;
782            } else {
783                if ( sliderInstance.data( 'loop' ) ) {
784                    if ( currentSlideIndex === 0 ) {
785                        currentSlideIndex = numberOfSlides;
786                    } else if ( currentSlideIndex > numberOfSlides ) {
787                        currentSlideIndex = currentSlideIndex - numberOfSlides;
788                    }
789                } else {
790                    currentSlideIndex = currentSlideIndex + 1;
791                }
792            }
793            sliderInstance.find( '.swift-slider-pagination .dot' ).removeClass( 'active' );
794            if ( jQuery.isNumeric(currentSlideIndex) ) {
795                sliderInstance.find( '.swift-slider-pagination .dot:nth-child(' + currentSlideIndex + ')' ).addClass( 'active' );
796            }
797
798            // Set curtain controls
799            if ( currentSlideID > 1 ) {
800                sliderInstance.find( '.swift-scroll-indicator' ).fadeOut( 300 );
801            } else {
802                sliderInstance.find( '.swift-scroll-indicator' ).fadeIn( 300 );
803            }
804
805            if ( currentSlideID === numberOfSlides && ssContinue ) {
806                setTimeout(
807                    function() {
808                        sliderInstance.find( '.swift-slider-continue' ).removeClass( 'continue-hidden' );
809                    }, 600
810                );
811            } else {
812                setTimeout(
813                    function() {
814                        //sliderInstance.find( '.swift-slider-continue' ).addClass( 'continue-hidden' );
815                    }, 300
816                );
817            }
818
819            // Set controls style based on the slide
820            sliderInstance.find( '.swift-slider-pagination, .swift-slider-prev, .swift-slider-next, .swift-slider-continue' ).removeClass( 'dark' ).removeClass( 'light' ).addClass( currentSlide.data( 'style' ) );
821
822            if ( currentSlideIndex === 1 && !sliderInstance.data( 'loop' ) ) {
823                sliderInstance.find( '.swift-slider-prev' ).css( 'display', 'none' );
824                sliderInstance.find( '.swift-slider-next' ).css( 'display', 'block' );
825            } else if ( currentSlideIndex === sliderInstance.find( '.swiper-slide' ).length && !sliderInstance.data( 'loop' ) ) {
826                sliderInstance.find( '.swift-slider-prev' ).css( 'display', 'block' );
827                sliderInstance.find( '.swift-slider-next' ).css( 'display', 'none' );
828            } else {
829                sliderInstance.find( '.swift-slider-prev' ).css( 'display', 'block' );
830                sliderInstance.find( '.swift-slider-next' ).css( 'display', 'block' );
831            }
832        },
833        slideTransitionEnd: function( e, delay ) {
834            var sliderObject = e,
835                sliderInstance = jQuery( sliderObject.container ),
836                currentSlide = jQuery( e.activeSlide() ),
837                currentIndex = e.activeIndex >= 0 ? e.activeIndex : 1,
838                currentSlideID = currentSlide.data( 'slide-id' ) ? parseInt( currentSlide.data( 'slide-id' ), 10 ) : 1,
839                timeoutDelay = delay || 0,
840                pagination = sliderInstance.find( '.swift-slider-pagination' ),
841                numberOfSlides = pagination.find( '.dot' ).length,
842                sliderPrev = jQuery( '.swift-slider-prev' ).find( 'h4' ),
843                sliderNext = jQuery( '.swift-slider-next' ).find( 'h4' ),
844                prevSlideTitle = currentSlideID === 1 ? sliderInstance.find( '.swiper-slide[data-slide-id="' + numberOfSlides + '"]' ).data( 'slide-title' ) : sliderInstance.find( '.swiper-slide[data-slide-id="' + (currentSlideID - 1) + '"]' ).data( 'slide-title' ),
845                nextSlideTitle = currentSlideID === numberOfSlides ? sliderInstance.find( '.swiper-slide[data-slide-id="1"]' ).data( 'slide-title' ) : sliderInstance.find( '.swiper-slide[data-slide-id="' + (currentSlideID + 1) + '"]' ).data( 'slide-title' );
846
847            // Resize the sliders
848            SWIFTSLIDER.resizeSliders( sliderInstance );
849
850            // Set next/previous navigation titles
851            sliderPrev.text( prevSlideTitle );
852            sliderNext.text( nextSlideTitle );
853
854            // Set content for each slide
855            sliderInstance.find( '.swiper-slide' ).each(
856                function( i ) {
857                    var slide = jQuery( this ),
858                        slideID = slide.data( 'slide-id' ),
859                        slideCaption = slide.find( '.caption-content' ),
860                        slideVideo = slide.find( '.video-wrap > video' ).first(),
861                        slideColour = slide.data('header-style'),
862                        slideHasVideo = false;
863
864                    // Check if there is a video
865                    if ( slideVideo.length > 0 ) {
866                        slideHasVideo = true;
867                    }
868
869                    // Remove video if mobile browser or not supported
870                    if ( slideHasVideo ) {
871                        jQuery.canVideoautoplay(function ( canAutoplay ) {
872                            if (!canAutoplay && !isAndroid) {
873                                slideVideo.remove();
874                                slideHasVideo = false;
875                            }
876                        });
877                    }
878
879                    // If has video, then pause it & set to start point
880                    if ( slideHasVideo ) {
881
882                        slideVideo.get( 0 ).pause();
883                        if ( slideVideo.get( 0 ).currentTime !== 0 ) {
884                            slideVideo.get( 0 ).currentTime = 0;
885                        }
886                    }
887
888                    // Reset caption position & opacity of other slides
889                    if ( slideID !== currentSlideID && slideCaption.length > 0 ) {
890                        slideCaption.css(
891                            {
892                                'margin-top': '',
893                                'padding-top': '',
894                                'padding-bottom': '',
895                                'opacity': '0'
896                            }
897                        ).removeClass('caption-active');
898                    }
899
900                    // animate current slide content
901                    if ( slideID === currentSlideID ) {
902
903                        if ( sliderInstance.is(':in-viewport') && ( body.hasClass('header-naked-light') || body.hasClass('header-naked-dark')) && $window.scrollTop() < 1 ) {
904                            jQuery('.header-wrap').attr('data-style', slideColour);
905                        }
906
907                        // Play the active slide video, if there is one
908                        setTimeout( function() {
909                            if ( slideHasVideo ) {
910                                if ( sliderInstance.is(':in-viewport') && !slideVideo.hasClass('finished') ) {
911                                    if (slideVideo.parents('.swiper-slide-active').length > 0) {
912                                        slideVideo.get( 0 ).play();
913                                    }
914                                } else {
915                                    slideVideo.get( 0 ).pause();
916                                }
917                            }
918
919                            // Fade in the current slide content
920                            if ( slideCaption.length > 0 ) {
921                                var captionHeight = slideCaption.height();
922
923                                slideCaption.addClass('caption-active');
924                                slideCaption.css( 'margin-top', -captionHeight / 2 ).stop().animate(
925                                    {
926                                        'opacity': 1,
927                                        'padding-top': 0,
928                                        'padding-bottom': 0
929                                    }, 800, 'easeOutQuart'
930                                );
931                            }
932                        }, timeoutDelay );
933                    }
934                }
935            );
936        },
937        setSliderContent: function( sliderInstance ) {
938
939            sliderInstance.find( '.swiper-slide' ).each(
940                function() {
941
942                    var content = jQuery( this ).find( '.caption-content' ),
943                        contentHeight = content.height();
944
945                    // Set content vertically center
946                    content.css( 'margin-top', -contentHeight / 2 );
947
948                }
949            );
950        }
951    };
952
953    var onReady = {
954        init: function() {
955            if ( jQuery( '.swift-slider' ).length > 0 ) {
956                SWIFTSLIDER.init();
957            }
958        }
959    };
960
961    jQuery( document ).ready( onReady.init );
962
963})( jQuery );
964
965/*
966 * SwiftSwiper 2.7.5
967 * Mobile touch slider and framework with hardware accelerated transitions
968 *
969 * http://www.idangero.us/sliders/swiper/
970 *
971 * Copyright 2010-2015, Vladimir Kharlampidi
972 * The iDangero.us
973 * http://www.idangero.us/
974 *
975 * Licensed under GPL & MIT
976 *
977 * Released on: January 28, 2015
978*/
979var SwiftSwiper = function (selector, params) {
980    'use strict';
981
982    /*=========================
983      A little bit dirty but required part for IE8 and old FF support
984      ===========================*/
985    if (!document.body.outerHTML && document.body.__defineGetter__) {
986        if (HTMLElement) {
987            var element = HTMLElement.prototype;
988            if (element.__defineGetter__) {
989                element.__defineGetter__('outerHTML', function () { return new XMLSerializer().serializeToString(this); });
990            }
991        }
992    }
993
994    if (!window.getComputedStyle) {
995        window.getComputedStyle = function (el, pseudo) {
996            this.el = el;
997            this.getPropertyValue = function (prop) {
998                var re = /(\-([a-z]){1})/g;
999                if (prop === 'float') prop = 'styleFloat';
1000                if (re.test(prop)) {
1001                    prop = prop.replace(re, function () {
1002                        return arguments[2].toUpperCase();
1003                    });
1004                }
1005                return el.currentStyle[prop] ? el.currentStyle[prop] : null;
1006            };
1007            return this;
1008        };
1009    }
1010    if (!Array.prototype.indexOf) {
1011        Array.prototype.indexOf = function (obj, start) {
1012            for (var i = (start || 0), j = this.length; i < j; i++) {
1013                if (this[i] === obj) { return i; }
1014            }
1015            return -1;
1016        };
1017    }
1018    if (!document.querySelectorAll) {
1019        if (!window.jQuery) return;
1020    }
1021    function $$(selector, context) {
1022        if (document.querySelectorAll)
1023            return (context || document).querySelectorAll(selector);
1024        else
1025            return jQuery(selector, context);
1026    }
1027
1028    /*=========================
1029      Check for correct selector
1030      ===========================*/
1031    if (typeof selector === 'undefined') return;
1032
1033    if (!(selector.nodeType)) {
1034        if ($$(selector).length === 0) return;
1035    }
1036
1037     /*=========================
1038      _this
1039      ===========================*/
1040    var _this = this;
1041
1042     /*=========================
1043      Default Flags and vars
1044      ===========================*/
1045    _this.touches = {
1046        start: 0,
1047        startX: 0,
1048        startY: 0,
1049        current: 0,
1050        currentX: 0,
1051        currentY: 0,
1052        diff: 0,
1053        abs: 0
1054    };
1055    _this.positions = {
1056        start: 0,
1057        abs: 0,
1058        diff: 0,
1059        current: 0
1060    };
1061    _this.times = {
1062        start: 0,
1063        end: 0
1064    };
1065
1066    _this.id = (new Date()).getTime();
1067    _this.container = (selector.nodeType) ? selector : $$(selector)[0];
1068    _this.isTouched = false;
1069    _this.isMoved = false;
1070    _this.activeIndex = 0;
1071    _this.centerIndex = 0;
1072    _this.activeLoaderIndex = 0;
1073    _this.activeLoopIndex = 0;
1074    _this.previousIndex = null;
1075    _this.velocity = 0;
1076    _this.snapGrid = [];
1077    _this.slidesGrid = [];
1078    _this.imagesToLoad = [];
1079    _this.imagesLoaded = 0;
1080    _this.wrapperLeft = 0;
1081    _this.wrapperRight = 0;
1082    _this.wrapperTop = 0;
1083    _this.wrapperBottom = 0;
1084    _this.isAndroid = navigator.userAgent.toLowerCase().indexOf('android') >= 0;
1085    var wrapper, slideSize, wrapperSize, direction, isScrolling, containerSize;
1086
1087    /*=========================
1088      Default Parameters
1089      ===========================*/
1090    var defaults = {
1091        eventTarget: 'wrapper', // or 'container'
1092        mode : 'horizontal', // or 'vertical'
1093        touchRatio : 1,
1094        speed : 300,
1095        freeMode : false,
1096        freeModeFluid : false,
1097        momentumRatio: 1,
1098        momentumBounce: true,
1099        momentumBounceRatio: 1,
1100        slidesPerView : 1,
1101        slidesPerGroup : 1,
1102        slidesPerViewFit: true, //Fit to slide when spv "auto" and slides larger than container
1103        simulateTouch : true,
1104        followFinger : true,
1105        shortSwipes : true,
1106        longSwipesRatio: 0.5,
1107        moveStartThreshold: false,
1108        onlyExternal : false,
1109        createPagination : true,
1110        pagination : false,
1111        paginationElement: 'span',
1112        paginationClickable: false,
1113        paginationAsRange: true,
1114        resistance : true, // or false or 100%
1115        scrollContainer : false,
1116        preventLinks : true,
1117        preventLinksPropagation: false,
1118        noSwiping : false, // or class
1119        noSwipingClass : 'swiper-no-swiping', //:)
1120        initialSlide: 0,
1121        keyboardControl: false,
1122        mousewheelControl : false,
1123        mousewheelControlForceToAxis : false,
1124        useCSS3Transforms : true,
1125        // Autoplay
1126        autoplay: false,
1127        autoplayDisableOnInteraction: true,
1128        autoplayStopOnLast: false,
1129        //Loop mode
1130        loop: false,
1131        loopAdditionalSlides: 0,
1132        // Round length values
1133        roundLengths: false,
1134        //Auto Height
1135        calculateHeight: false,
1136        //Apply CSS for width and/or height
1137        cssWidthAndHeight: false, // or true or 'width' or 'height'
1138        //Images Preloader
1139        updateOnImagesReady : true,
1140        //Form elements
1141        releaseFormElements : true,
1142        //Watch for active slide, useful when use effects on different slide states
1143        watchActiveIndex: false,
1144        //Slides Visibility Fit
1145        visibilityFullFit : false,
1146        //Slides Offset
1147        offsetPxBefore : 0,
1148        offsetPxAfter : 0,
1149        offsetSlidesBefore : 0,
1150        offsetSlidesAfter : 0,
1151        centeredSlides: false,
1152        //Queue callbacks
1153        queueStartCallbacks : false,
1154        queueEndCallbacks : false,
1155        //Auto Resize
1156        autoResize : true,
1157        resizeReInit : false,
1158        //DOMAnimation
1159        DOMAnimation : true,
1160        //Slides Loader
1161        loader: {
1162            slides: [], //array with slides
1163            slidesHTMLType: 'inner', // or 'outer'
1164            surroundGroups: 1, //keep preloaded slides groups around view
1165            logic: 'reload', //or 'change'
1166            loadAllSlides: false
1167        },
1168        // One way swipes
1169        swipeToPrev: true,
1170        swipeToNext: true,
1171        //Namespace
1172        slideElement: 'div',
1173        slideClass: 'swiper-slide',
1174        slideActiveClass: 'swiper-slide-active',
1175        slideVisibleClass: 'swiper-slide-visible',
1176        slideDuplicateClass: 'swiper-slide-duplicate',
1177        wrapperClass: 'swiper-wrapper',
1178        paginationElementClass: 'swiper-pagination-switch',
1179        paginationActiveClass: 'swiper-active-switch',
1180        paginationVisibleClass: 'swiper-visible-switch'
1181    };
1182    params = params || {};
1183    for (var prop in defaults) {
1184        if (prop in params && typeof params[prop] === 'object') {
1185            for (var subProp in defaults[prop]) {
1186                if (! (subProp in params[prop])) {
1187                    params[prop][subProp] = defaults[prop][subProp];
1188                }
1189            }
1190        }
1191        else if (! (prop in params)) {
1192            params[prop] = defaults[prop];
1193        }
1194    }
1195    _this.params = params;
1196    if (params.scrollContainer) {
1197        params.freeMode = true;
1198        params.freeModeFluid = true;
1199    }
1200    if (params.loop) {
1201        params.resistance = '100%';
1202    }
1203    var isH = params.mode === 'horizontal';
1204
1205    /*=========================
1206      Define Touch Events
1207      ===========================*/
1208    var desktopEvents = ['mousedown', 'mousemove', 'mouseup'];
1209    if (_this.browser.ie10) desktopEvents = ['MSPointerDown', 'MSPointerMove', 'MSPointerUp'];
1210    if (_this.browser.ie11) desktopEvents = ['pointerdown', 'pointermove', 'pointerup'];
1211
1212    _this.touchEvents = {
1213        touchStart : _this.support.touch || !params.simulateTouch  ? 'touchstart' : desktopEvents[0],
1214        touchMove : _this.support.touch || !params.simulateTouch ? 'touchmove' : desktopEvents[1],
1215        touchEnd : _this.support.touch || !params.simulateTouch ? 'touchend' : desktopEvents[2]
1216    };
1217
1218    /*=========================
1219      Wrapper
1220      ===========================*/
1221    for (var i = _this.container.childNodes.length - 1; i >= 0; i--) {
1222        if (_this.container.childNodes[i].className) {
1223            var _wrapperClasses = _this.container.childNodes[i].className.split(/\s+/);
1224            for (var j = 0; j < _wrapperClasses.length; j++) {
1225                if (_wrapperClasses[j] === params.wrapperClass) {
1226                    wrapper = _this.container.childNodes[i];
1227                }
1228            }
1229        }
1230    }
1231
1232    _this.wrapper = wrapper;
1233    /*=========================
1234      Slide API
1235      ===========================*/
1236    _this._extendSwiftSwiperSlide = function  (el) {
1237        el.append = function () {
1238            if (params.loop) {
1239                el.insertAfter(_this.slides.length - _this.loopedSlides);
1240            }
1241            else {
1242                _this.wrapper.appendChild(el);
1243                _this.reInit();
1244            }
1245
1246            return el;
1247        };
1248        el.prepend = function () {
1249            if (params.loop) {
1250                _this.wrapper.insertBefore(el, _this.slides[_this.loopedSlides]);
1251                _this.removeLoopedSlides();
1252                _this.calcSlides();
1253                _this.createLoop();
1254            }
1255            else {
1256                _this.wrapper.insertBefore(el, _this.wrapper.firstChild);
1257            }
1258            _this.reInit();
1259            return el;
1260        };
1261        el.insertAfter = function (index) {
1262            if (typeof index === 'undefined') return false;
1263            var beforeSlide;
1264
1265            if (params.loop) {
1266                beforeSlide = _this.slides[index + 1 + _this.loopedSlides];
1267                if (beforeSlide) {
1268                    _this.wrapper.insertBefore(el, beforeSlide);
1269                }
1270                else {
1271                    _this.wrapper.appendChild(el);
1272                }
1273                _this.removeLoopedSlides();
1274                _this.calcSlides();
1275                _this.createLoop();
1276            }
1277            else {
1278                beforeSlide = _this.slides[index + 1];
1279                _this.wrapper.insertBefore(el, beforeSlide);
1280            }
1281            _this.reInit();
1282            return el;
1283        };
1284        el.clone = function () {
1285            return _this._extendSwiftSwiperSlide(el.cloneNode(true));
1286        };
1287        el.remove = function () {
1288            _this.wrapper.removeChild(el);
1289            _this.reInit();
1290        };
1291        el.html = function (html) {
1292            if (typeof html === 'undefined') {
1293                return el.innerHTML;
1294            }
1295            else {
1296                el.innerHTML = html;
1297                return el;
1298            }
1299        };
1300        el.index = function () {
1301            var index;
1302            for (var i = _this.slides.length - 1; i >= 0; i--) {
1303                if (el === _this.slides[i]) index = i;
1304            }
1305            return index;
1306        };
1307        el.isActive = function () {
1308            if (el.index() === _this.activeIndex) return true;
1309            else return false;
1310        };
1311        if (!el.swiperSlideDataStorage) el.swiperSlideDataStorage = {};
1312        el.getData = function (name) {
1313            return el.swiperSlideDataStorage[name];
1314        };
1315        el.setData = function (name, value) {
1316            el.swiperSlideDataStorage[name] = value;
1317            return el;
1318        };
1319        el.data = function (name, value) {
1320            if (typeof value === 'undefined') {
1321                return el.getAttribute('data-' + name);
1322            }
1323            else {
1324                el.setAttribute('data-' + name, value);
1325                return el;
1326            }
1327        };
1328        el.getWidth = function (outer, round) {
1329            return _this.h.getWidth(el, outer, round);
1330        };
1331        el.getHeight = function (outer, round) {
1332            return _this.h.getHeight(el, outer, round);
1333        };
1334        el.getOffset = function () {
1335            return _this.h.getOffset(el);
1336        };
1337        return el;
1338    };
1339
1340    //Calculate information about number of slides
1341    _this.calcSlides = function (forceCalcSlides) {
1342        var oldNumber = _this.slides ? _this.slides.length : false;
1343        _this.slides = [];
1344        _this.displaySlides = [];
1345        for (var i = 0; i < _this.wrapper.childNodes.length; i++) {
1346            if (_this.wrapper.childNodes[i].className) {
1347                var _className = _this.wrapper.childNodes[i].className;
1348                var _slideClasses = _className.split(/\s+/);
1349                for (var j = 0; j < _slideClasses.length; j++) {
1350                    if (_slideClasses[j] === params.slideClass) {
1351                        _this.slides.push(_this.wrapper.childNodes[i]);
1352                    }
1353                }
1354            }
1355        }
1356        for (i = _this.slides.length - 1; i >= 0; i--) {
1357            _this._extendSwiftSwiperSlide(_this.slides[i]);
1358        }
1359        if (oldNumber === false) return;
1360        if (oldNumber !== _this.slides.length || forceCalcSlides) {
1361
1362            // Number of slides has been changed
1363            removeSlideEvents();
1364            addSlideEvents();
1365            _this.updateActiveSlide();
1366            if (_this.params.pagination) _this.createPagination();
1367            _this.callPlugins('numberOfSlidesChanged');
1368        }
1369    };
1370
1371    //Create Slide
1372    _this.createSlide = function (html, slideClassList, el) {
1373        slideClassList = slideClassList || _this.params.slideClass;
1374        el = el || params.slideElement;
1375        var newSlide = document.createElement(el);
1376        newSlide.innerHTML = html || '';
1377        newSlide.className = slideClassList;
1378        return _this._extendSwiftSwiperSlide(newSlide);
1379    };
1380
1381    //Append Slide
1382    _this.appendSlide = function (html, slideClassList, el) {
1383        if (!html) return;
1384        if (html.nodeType) {
1385            return _this._extendSwiftSwiperSlide(html).append();
1386        }
1387        else {
1388            return _this.createSlide(html, slideClassList, el).append();
1389        }
1390    };
1391    _this.prependSlide = function (html, slideClassList, el) {
1392        if (!html) return;
1393        if (html.nodeType) {
1394            return _this._extendSwiftSwiperSlide(html).prepend();
1395        }
1396        else {
1397            return _this.createSlide(html, slideClassList, el).prepend();
1398        }
1399    };
1400    _this.insertSlideAfter = function (index, html, slideClassList, el) {
1401        if (typeof index === 'undefined') return false;
1402        if (html.nodeType) {
1403            return _this._extendSwiftSwiperSlide(html).insertAfter(index);
1404        }
1405        else {
1406            return _this.createSlide(html, slideClassList, el).insertAfter(index);
1407        }
1408    };
1409    _this.removeSlide = function (index) {
1410        if (_this.slides[index]) {
1411            if (params.loop) {
1412                if (!_this.slides[index + _this.loopedSlides]) return false;
1413                _this.slides[index + _this.loopedSlides].remove();
1414                _this.removeLoopedSlides();
1415                _this.calcSlides();
1416                _this.createLoop();
1417            }
1418            else _this.slides[index].remove();
1419            return true;
1420        }
1421        else return false;
1422    };
1423    _this.removeLastSlide = function () {
1424        if (_this.slides.length > 0) {
1425            if (params.loop) {
1426                _this.slides[_this.slides.length - 1 - _this.loopedSlides].remove();
1427                _this.removeLoopedSlides();
1428                _this.calcSlides();
1429                _this.createLoop();
1430            }
1431            else _this.slides[_this.slides.length - 1].remove();
1432            return true;
1433        }
1434        else {
1435            return false;
1436        }
1437    };
1438    _this.removeAllSlides = function () {
1439        var num = _this.slides.length;
1440        for (var i = _this.slides.length - 1; i >= 0; i--) {
1441            _this.slides[i].remove();
1442            if (i === num - 1) {
1443                _this.setWrapperTranslate(0);
1444            }
1445        }
1446    };
1447    _this.getSlide = function (index) {
1448        return _this.slides[index];
1449    };
1450    _this.getLastSlide = function () {
1451        return _this.slides[_this.slides.length - 1];
1452    };
1453    _this.getFirstSlide = function () {
1454        return _this.slides[0];
1455    };
1456
1457    //Currently Active Slide
1458    _this.activeSlide = function () {
1459        return _this.slides[_this.activeIndex];
1460    };
1461
1462    /*=========================
1463     Wrapper for Callbacks : Allows additive callbacks via function arrays
1464     ===========================*/
1465    _this.fireCallback = function () {
1466        var callback = arguments[0];
1467        if (Object.prototype.toString.call(callback) === '[object Array]') {
1468            for (var i = 0; i < callback.length; i++) {
1469                if (typeof callback[i] === 'function') {
1470                    callback[i](arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
1471                }
1472            }
1473        } else if (Object.prototype.toString.call(callback) === '[object String]') {
1474            if (params['on' + callback]) _this.fireCallback(params['on' + callback], arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
1475        } else {
1476            callback(arguments[1], arguments[2], arguments[3], arguments[4], arguments[5]);
1477        }
1478    };
1479    function isArray(obj) {
1480        if (Object.prototype.toString.apply(obj) === '[object Array]') return true;
1481        return false;
1482    }
1483
1484    /**
1485     * Allows user to add callbacks, rather than replace them
1486     * @param callback
1487     * @param func
1488     * @return {*}
1489     */
1490    _this.addCallback = function (callback, func) {
1491        var _this = this, tempFunc;
1492        if (_this.params['on' + callback]) {
1493            if (isArray(this.params['on' + callback])) {
1494                return this.params['on' + callback].push(func);
1495            } else if (typeof this.params['on' + callback] === 'function') {
1496                tempFunc = this.params['on' + callback];
1497                this.params['on' + callback] = [];
1498                this.params['on' + callback].push(tempFunc);
1499                return this.params['on' + callback].push(func);
1500            }
1501        } else {
1502            this.params['on' + callback] = [];
1503            return this.params['on' + callback].push(func);
1504        }
1505    };
1506    _this.removeCallbacks = function (callback) {
1507        if (_this.params['on' + callback]) {
1508            _this.params['on' + callback] = null;
1509        }
1510    };
1511
1512    /*=========================
1513      Plugins API
1514      ===========================*/
1515    var _plugins = [];
1516    for (var plugin in _this.plugins) {
1517        if (params[plugin]) {
1518            var p = _this.plugins[plugin](_this, params[plugin]);
1519            if (p) _plugins.push(p);
1520        }
1521    }
1522    _this.callPlugins = function (method, args) {
1523        if (!args) args = {};
1524        for (var i = 0; i < _plugins.length; i++) {
1525            if (method in _plugins[i]) {
1526                _plugins[i][method](args);
1527            }
1528        }
1529    };
1530
1531    /*=========================
1532      Windows Phone 8 Fix
1533      ===========================*/
1534    if ((_this.browser.ie10 || _this.browser.ie11) && !params.onlyExternal) {
1535        _this.wrapper.classList.add('swiper-wp8-' + (isH ? 'horizontal' : 'vertical'));
1536    }
1537
1538    /*=========================
1539      Free Mode Class
1540      ===========================*/
1541    if (params.freeMode) {
1542        _this.container.className += ' swiper-free-mode';
1543    }
1544
1545    /*==================================================
1546        Init/Re-init/Resize Fix
1547    ====================================================*/
1548    _this.initialized = false;
1549    _this.init = function (force, forceCalcSlides) {
1550        var _width = _this.h.getWidth(_this.container, false, params.roundLengths);
1551        var _height = _this.h.getHeight(_this.container, false, params.roundLengths);
1552        if (_width === _this.width && _height === _this.height && !force) return;
1553
1554        _this.width = _width;
1555        _this.height = _height;
1556
1557        var slideWidth, slideHeight, slideMaxHeight, wrapperWidth, wrapperHeight, slideLeft;
1558        var i; // loop index variable to avoid JSHint W004 / W038
1559        containerSize = isH ? _width : _height;
1560        var wrapper = _this.wrapper;
1561
1562        if (force) {
1563            _this.calcSlides(forceCalcSlides);
1564        }
1565
1566        if (params.slidesPerView === 'auto') {
1567            //Auto mode
1568            var slidesWidth = 0;
1569            var slidesHeight = 0;
1570
1571            //Unset Styles
1572            if (params.slidesOffset > 0) {
1573                wrapper.style.paddingLeft = '';
1574                wrapper.style.paddingRight = '';
1575                wrapper.style.paddingTop = '';
1576                wrapper.style.paddingBottom = '';
1577            }
1578            wrapper.style.width = '';
1579            wrapper.style.height = '';
1580            if (params.offsetPxBefore > 0) {
1581                if (isH) _this.wrapperLeft = params.offsetPxBefore;
1582                else _this.wrapperTop = params.offsetPxBefore;
1583            }
1584            if (params.offsetPxAfter > 0) {
1585                if (isH) _this.wrapperRight = params.offsetPxAfter;
1586                else _this.wrapperBottom = params.offsetPxAfter;
1587            }
1588
1589            if (params.centeredSlides) {
1590                if (isH) {
1591                    _this.wrapperLeft = (containerSize - this.slides[0].getWidth(true, params.roundLengths)) / 2;
1592                    _this.wrapperRight = (containerSize - _this.slides[_this.slides.length - 1].getWidth(true, params.roundLengths)) / 2;
1593                }
1594                else {
1595                    _this.wrapperTop = (containerSize - _this.slides[0].getHeight(true, params.roundLengths)) / 2;
1596                    _this.wrapperBottom = (containerSize - _this.slides[_this.slides.length - 1].getHeight(true, params.roundLengths)) / 2;
1597                }
1598            }
1599
1600            if (isH) {
1601                if (_this.wrapperLeft >= 0) wrapper.style.paddingLeft = _this.wrapperLeft + 'px';
1602                if (_this.wrapperRight >= 0) wrapper.style.paddingRight = _this.wrapperRight + 'px';
1603            }
1604            else {
1605                if (_this.wrapperTop >= 0) wrapper.style.paddingTop = _this.wrapperTop + 'px';
1606                if (_this.wrapperBottom >= 0) wrapper.style.paddingBottom = _this.wrapperBottom + 'px';
1607            }
1608            slideLeft = 0;
1609            var centeredSlideLeft = 0;
1610            _this.snapGrid = [];
1611            _this.slidesGrid = [];
1612
1613            slideMaxHeight = 0;
1614            for (i = 0; i < _this.slides.length; i++) {
1615                slideWidth = _this.slides[i].getWidth(true, params.roundLengths);
1616                slideHeight = _this.slides[i].getHeight(true, params.roundLengths);
1617                if (params.calculateHeight) {
1618                    slideMaxHeight = Math.max(slideMaxHeight, slideHeight);
1619                }
1620                var _slideSize = isH ? slideWidth : slideHeight;
1621                if (params.centeredSlides) {
1622                    var nextSlideWidth = i === _this.slides.length - 1 ? 0 : _this.slides[i + 1].getWidth(true, params.roundLengths);
1623                    var nextSlideHeight = i === _this.slides.length - 1 ? 0 : _this.slides[i + 1].getHeight(true, params.roundLengths);
1624                    var nextSlideSize = isH ? nextSlideWidth : nextSlideHeight;
1625                    if (_slideSize > containerSize) {
1626                        if (params.slidesPerViewFit) {
1627                            _this.snapGrid.push(slideLeft + _this.wrapperLeft);
1628                            _this.snapGrid.push(slideLeft + _slideSize - containerSize + _this.wrapperLeft);
1629                        }
1630                        else {
1631                            for (var j = 0; j <= Math.floor(_slideSize / (containerSize + _this.wrapperLeft)); j++) {
1632                                if (j === 0) _this.snapGrid.push(slideLeft + _this.wrapperLeft);
1633                                else _this.snapGrid.push(slideLeft + _this.wrapperLeft + containerSize * j);
1634                            }
1635                        }
1636                        _this.slidesGrid.push(slideLeft + _this.wrapperLeft);
1637                    }
1638                    else {
1639                        _this.snapGrid.push(centeredSlideLeft);
1640                        _this.slidesGrid.push(centeredSlideLeft);
1641                    }
1642                    centeredSlideLeft += _slideSize / 2 + nextSlideSize / 2;
1643                }
1644                else {
1645                    if (_slideSize > containerSize) {
1646                        if (params.slidesPerViewFit) {
1647                            _this.snapGrid.push(slideLeft);
1648                            _this.snapGrid.push(slideLeft + _slideSize - containerSize);
1649                        }
1650                        else {
1651                            if (containerSize !== 0) {
1652                                for (var k = 0; k <= Math.floor(_slideSize / containerSize); k++) {
1653                                    _this.snapGrid.push(slideLeft + containerSize * k);
1654                                }
1655                            }
1656                            else {
1657                                _this.snapGrid.push(slideLeft);
1658                            }
1659                        }
1660
1661                    }
1662                    else {
1663                        _this.snapGrid.push(slideLeft);
1664                    }
1665                    _this.slidesGrid.push(slideLeft);
1666                }
1667
1668                slideLeft += _slideSize;
1669
1670                slidesWidth += slideWidth;
1671                slidesHeight += slideHeight;
1672            }
1673            if (params.calculateHeight) _this.height = slideMaxHeight;
1674            if (isH) {
1675                wrapperSize = slidesWidth + _this.wrapperRight + _this.wrapperLeft;
1676                if (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'height') {
1677                    wrapper.style.width = (slidesWidth) + 'px';
1678                }
1679                if (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'width') {
1680                    wrapper.style.height = (_this.height) + 'px';
1681                }
1682            }
1683            else {
1684                if (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'height') {
1685                    wrapper.style.width = (_this.width) + 'px';
1686                }
1687                if (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'width') {
1688                    wrapper.style.height = (slidesHeight) + 'px';
1689                }
1690                wrapperSize = slidesHeight + _this.wrapperTop + _this.wrapperBottom;
1691            }
1692
1693        }
1694        else if (params.scrollContainer) {
1695            //Scroll Container
1696            wrapper.style.width = '';
1697            wrapper.style.height = '';
1698            wrapperWidth = _this.slides[0].getWidth(true, params.roundLengths);
1699            wrapperHeight = _this.slides[0].getHeight(true, params.roundLengths);
1700            wrapperSize = isH ? wrapperWidth : wrapperHeight;
1701            wrapper.style.width = wrapperWidth + 'px';
1702            wrapper.style.height = wrapperHeight + 'px';
1703            slideSize = isH ? wrapperWidth : wrapperHeight;
1704
1705        }
1706        else {
1707            //For usual slides
1708            if (params.calculateHeight) {
1709                slideMaxHeight = 0;
1710                wrapperHeight = 0;
1711                //ResetWrapperSize
1712                if (!isH) _this.container.style.height = '';
1713                wrapper.style.height = '';
1714
1715                for (i = 0; i < _this.slides.length; i++) {
1716                    //ResetSlideSize
1717                    _this.slides[i].style.height = '';
1718                    slideMaxHeight = Math.max(_this.slides[i].getHeight(true), slideMaxHeight);
1719                    if (!isH) wrapperHeight += _this.slides[i].getHeight(true);
1720                }
1721                slideHeight = slideMaxHeight;
1722                _this.height = slideHeight;
1723
1724                if (isH) wrapperHeight = slideHeight;
1725                else {
1726                    containerSize = slideHeight;
1727                    _this.container.style.height = containerSize + 'px';
1728                }
1729            }
1730            else {
1731                slideHeight = isH ? _this.height : _this.height / params.slidesPerView;
1732                if (params.roundLengths) slideHeight = Math.ceil(slideHeight);
1733                wrapperHeight = isH ? _this.height : _this.slides.length * slideHeight;
1734            }
1735            slideWidth = isH ? _this.width / params.slidesPerView : _this.width;
1736            if (params.roundLengths) slideWidth = Math.ceil(slideWidth);
1737            wrapperWidth = isH ? _this.slides.length * slideWidth : _this.width;
1738            slideSize = isH ? slideWidth : slideHeight;
1739
1740            if (params.offsetSlidesBefore > 0) {
1741                if (isH) _this.wrapperLeft = slideSize * params.offsetSlidesBefore;
1742                else _this.wrapperTop = slideSize * params.offsetSlidesBefore;
1743            }
1744            if (params.offsetSlidesAfter > 0) {
1745                if (isH) _this.wrapperRight = slideSize * params.offsetSlidesAfter;
1746                else _this.wrapperBottom = slideSize * params.offsetSlidesAfter;
1747            }
1748            if (params.offsetPxBefore > 0) {
1749                if (isH) _this.wrapperLeft = params.offsetPxBefore;
1750                else _this.wrapperTop = params.offsetPxBefore;
1751            }
1752            if (params.offsetPxAfter > 0) {
1753                if (isH) _this.wrapperRight = params.offsetPxAfter;
1754                else _this.wrapperBottom = params.offsetPxAfter;
1755            }
1756            if (params.centeredSlides) {
1757                if (isH) {
1758                    _this.wrapperLeft = (containerSize - slideSize) / 2;
1759                    _this.wrapperRight = (containerSize - slideSize) / 2;
1760                }
1761                else {
1762                    _this.wrapperTop = (containerSize - slideSize) / 2;
1763                    _this.wrapperBottom = (containerSize - slideSize) / 2;
1764                }
1765            }
1766            if (isH) {
1767                if (_this.wrapperLeft > 0) wrapper.style.paddingLeft = _this.wrapperLeft + 'px';
1768                if (_this.wrapperRight > 0) wrapper.style.paddingRight = _this.wrapperRight + 'px';
1769            }
1770            else {
1771                if (_this.wrapperTop > 0) wrapper.style.paddingTop = _this.wrapperTop + 'px';
1772                if (_this.wrapperBottom > 0) wrapper.style.paddingBottom = _this.wrapperBottom + 'px';
1773            }
1774
1775            wrapperSize = isH ? wrapperWidth + _this.wrapperRight + _this.wrapperLeft : wrapperHeight + _this.wrapperTop + _this.wrapperBottom;
1776            if (parseFloat(wrapperWidth) > 0 && (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'height')) {
1777                wrapper.style.width = wrapperWidth + 'px';
1778            }
1779            if (parseFloat(wrapperHeight) > 0 && (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'width')) {
1780                wrapper.style.height = wrapperHeight + 'px';
1781            }
1782            slideLeft = 0;
1783            _this.snapGrid = [];
1784            _this.slidesGrid = [];
1785            for (i = 0; i < _this.slides.length; i++) {
1786                _this.snapGrid.push(slideLeft);
1787                _this.slidesGrid.push(slideLeft);
1788                slideLeft += slideSize;
1789                if (parseFloat(slideWidth) > 0 && (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'height')) {
1790                    _this.slides[i].style.width = slideWidth + 'px';
1791                }
1792                if (parseFloat(slideHeight) > 0 && (!params.cssWidthAndHeight || params.cssWidthAndHeight === 'width')) {
1793                    _this.slides[i].style.height = slideHeight + 'px';
1794                }
1795            }
1796
1797        }
1798
1799        if (!_this.initialized) {
1800            _this.callPlugins('onFirstInit');
1801            if (params.onFirstInit) _this.fireCallback(params.onFirstInit, _this);
1802        }
1803        else {
1804            _this.callPlugins('onInit');
1805            if (params.onInit) _this.fireCallback(params.onInit, _this);
1806        }
1807        _this.initialized = true;
1808    };
1809
1810    _this.reInit = function (forceCalcSlides) {
1811        _this.init(true, forceCalcSlides);
1812    };
1813
1814    _this.resizeFix = function (reInit) {
1815        _this.callPlugins('beforeResizeFix');
1816
1817        setTimeout(function() {
1818            _this.init(params.resizeReInit || reInit);
1819
1820            // swipe to active slide in fixed mode
1821            if (!params.freeMode) {
1822                _this.swipeTo((params.loop ? _this.activeLoopIndex : _this.activeIndex), 0, false);
1823                // Fix autoplay
1824                if (params.autoplay) {
1825                    if (_this.support.transitions && typeof autoplayTimeoutId !== 'undefined') {
1826                        if (typeof autoplayTimeoutId !== 'undefined') {
1827                            clearTimeout(autoplayTimeoutId);
1828                            autoplayTimeoutId = undefined;
1829                            _this.startAutoplay();
1830                        }
1831                    }
1832                    else {
1833                        if (typeof autoplayIntervalId !== 'undefined') {
1834                            clearInterval(autoplayIntervalId);
1835                            autoplayIntervalId = undefined;
1836                            _this.startAutoplay();
1837                        }
1838                    }
1839                }
1840            }
1841            // move wrapper to the beginning in free mode
1842            else if (_this.getWrapperTranslate() < -maxWrapperPosition()) {
1843                _this.setWrapperTransition(0);
1844                _this.setWrapperTranslate(-maxWrapperPosition());
1845            }
1846
1847            _this.callPlugins('afterResizeFix');
1848        }, 100);
1849    };
1850
1851    /*==========================================
1852        Max and Min Positions
1853    ============================================*/
1854    function maxWrapperPosition() {
1855        var a = (wrapperSize - containerSize);
1856        if (params.freeMode) {
1857            a = wrapperSize - containerSize;
1858        }
1859        // if (params.loop) a -= containerSize;
1860        if (params.slidesPerView > _this.slides.length && !params.centeredSlides) {
1861            a = 0;
1862        }
1863        if (a < 0) a = 0;
1864        return a;
1865    }
1866
1867    /*==========================================
1868        Event Listeners
1869    ============================================*/
1870    function initEvents() {
1871        var bind = _this.h.addEventListener;
1872        var eventTarget = params.eventTarget === 'wrapper' ? _this.wrapper : _this.container;
1873        //Touch Events
1874        if (! (_this.browser.ie10 || _this.browser.ie11)) {
1875            if (_this.support.touch) {
1876                bind(eventTarget, 'touchstart', onTouchStart);
1877                bind(eventTarget, 'touchmove', onTouchMove);
1878                bind(eventTarget, 'touchend', onTouchEnd);
1879            }
1880            if (params.simulateTouch) {
1881                bind(eventTarget, 'mousedown', onTouchStart);
1882                bind(document, 'mousemove', onTouchMove);
1883                bind(document, 'mouseup', onTouchEnd);
1884            }
1885        }
1886        else {
1887            bind(eventTarget, _this.touchEvents.touchStart, onTouchStart);
1888            bind(document, _this.touchEvents.touchMove, onTouchMove);
1889            bind(document, _this.touchEvents.touchEnd, onTouchEnd);
1890        }
1891
1892        //Resize Event
1893        if (params.autoResize) {
1894            bind(window, 'resize', _this.resizeFix);
1895        }
1896        //Slide Events
1897        addSlideEvents();
1898        //Mousewheel
1899        _this._wheelEvent = false;
1900        if (params.mousewheelControl) {
1901            if (document.onmousewheel !== undefined) {
1902                _this._wheelEvent = 'mousewheel';
1903            }
1904            if (!_this._wheelEvent) {
1905                try {
1906                    new WheelEvent('wheel');
1907                    _this._wheelEvent = 'wheel';
1908                } catch (e) {}
1909            }
1910            if (!_this._wheelEvent) {
1911                _this._wheelEvent = 'DOMMouseScroll';
1912            }
1913            if (_this._wheelEvent) {
1914                bind(_this.container, _this._wheelEvent, handleMousewheel);
1915            }
1916        }
1917
1918        //Keyboard
1919        function _loadImage(img) {
1920            var image, src;
1921            var onReady = function () {
1922                if (typeof _this === 'undefined' || _this === null) return;
1923                if (_this.imagesLoaded !== undefined) _this.imagesLoaded++;
1924                if (_this.imagesLoaded === _this.imagesToLoad.length) {
1925                    _this.reInit();
1926                    if (params.onImagesReady) _this.fireCallback(params.onImagesReady, _this);
1927                }
1928            };
1929
1930            if (!img.complete) {
1931                src = (img.currentSrc || img.getAttribute('src'));
1932                if (src) {
1933                    image = new Image();
1934                    image.onload = onReady;
1935                    image.onerror = onReady;
1936                    image.src = src;
1937                } else {
1938                    onReady();
1939                }
1940
1941            } else {//image already loaded...
1942                onReady();
1943            }
1944        }
1945
1946        if (params.keyboardControl) {
1947            bind(document, 'keydown', handleKeyboardKeys);
1948        }
1949        if (params.updateOnImagesReady) {
1950            _this.imagesToLoad = $$('img', _this.container);
1951
1952            for (var i = 0; i < _this.imagesToLoad.length; i++) {
1953                _loadImage(_this.imagesToLoad[i]);
1954            }
1955        }
1956    }
1957
1958    //Remove Event Listeners
1959    _this.destroy = function (removeStyles) {
1960        var unbind = _this.h.removeEventListener;
1961        var eventTarget = params.eventTarget === 'wrapper' ? _this.wrapper : _this.container;
1962        //Touch Events
1963        if (! (_this.browser.ie10 || _this.browser.ie11)) {
1964            if (_this.support.touch) {
1965                unbind(eventTarget, 'touchstart', onTouchStart);
1966                unbind(eventTarget, 'touchmove', onTouchMove);
1967                unbind(eventTarget, 'touchend', onTouchEnd);
1968            }
1969            if (params.simulateTouch) {
1970                unbind(eventTarget, 'mousedown', onTouchStart);
1971                unbind(document, 'mousemove', onTouchMove);
1972                unbind(document, 'mouseup', onTouchEnd);
1973            }
1974        }
1975        else {
1976            unbind(eventTarget, _this.touchEvents.touchStart, onTouchStart);
1977            unbind(document, _this.touchEvents.touchMove, onTouchMove);
1978            unbind(document, _this.touchEvents.touchEnd, onTouchEnd);
1979        }
1980
1981        //Resize Event
1982        if (params.autoResize) {
1983            unbind(window, 'resize', _this.resizeFix);
1984        }
1985
1986        //Init Slide Events
1987        removeSlideEvents();
1988
1989        //Pagination
1990        if (params.paginationClickable) {
1991            removePaginationEvents();
1992        }
1993
1994        //Mousewheel
1995        if (params.mousewheelControl && _this._wheelEvent) {
1996            unbind(_this.container, _this._wheelEvent, handleMousewheel);
1997        }
1998
1999        //Keyboard
2000        if (params.keyboardControl) {
2001            unbind(document, 'keydown', handleKeyboardKeys);
2002        }
2003
2004        //Stop autoplay
2005        if (params.autoplay) {
2006            _this.stopAutoplay();
2007        }
2008        // Remove styles
2009        if (removeStyles) {
2010            _this.wrapper.removeAttribute('style');
2011            for (var i = 0; i < _this.slides.length; i++) {
2012                _this.slides[i].removeAttribute('style');
2013            }
2014        }
2015        // Plugins
2016        _this.callPlugins('onDestroy');
2017
2018        // Check jQuery/Zepto data
2019        if (window.jQuery && window.jQuery(_this.container).data('swiper')) {
2020            window.jQuery(_this.container).removeData('swiper');
2021        }
2022        if (window.Zepto && window.Zepto(_this.container).data('swiper')) {
2023            window.Zepto(_this.container).removeData('swiper');
2024        }
2025
2026        //Destroy variable
2027        _this = null;
2028    };
2029
2030    function addSlideEvents() {
2031        var bind = _this.h.addEventListener,
2032            i;
2033
2034        //Prevent Links Events
2035        if (params.preventLinks) {
2036            var links = $$('a', _this.container);
2037            for (i = 0; i < links.length; i++) {
2038                bind(links[i], 'click', preventClick);
2039            }
2040        }
2041        //Release Form Elements
2042        if (params.releaseFormElements) {
2043            var formElements = $$('input, textarea, select', _this.container);
2044            for (i = 0; i < formElements.length; i++) {
2045                bind(formElements[i], _this.touchEvents.touchStart, releaseForms, true);
2046                if (_this.support.touch && params.simulateTouch) {
2047                    bind(formElements[i], 'mousedown', releaseForms, true);
2048                }
2049            }
2050        }
2051
2052        //Slide Clicks & Touches
2053        if (params.onSlideClick) {
2054            for (i = 0; i < _this.slides.length; i++) {
2055                bind(_this.slides[i], 'click', slideClick);
2056            }
2057        }
2058        if (params.onSlideTouch) {
2059            for (i = 0; i < _this.slides.length; i++) {
2060                bind(_this.slides[i], _this.touchEvents.touchStart, slideTouch);
2061            }
2062        }
2063    }
2064    function removeSlideEvents() {
2065        var unbind = _this.h.removeEventListener,
2066            i;
2067
2068        //Slide Clicks & Touches
2069        if (params.onSlideClick) {
2070            for (i = 0; i < _this.slides.length; i++) {
2071                unbind(_this.slides[i], 'click', slideClick);
2072            }
2073        }
2074        if (params.onSlideTouch) {
2075            for (i = 0; i < _this.slides.length; i++) {
2076                unbind(_this.slides[i], _this.touchEvents.touchStart, slideTouch);
2077            }
2078        }
2079        //Release Form Elements
2080        if (params.releaseFormElements) {
2081            var formElements = $$('input, textarea, select', _this.container);
2082            for (i = 0; i < formElements.length; i++) {
2083                unbind(formElements[i], _this.touchEvents.touchStart, releaseForms, true);
2084                if (_this.support.touch && params.simulateTouch) {
2085                    unbind(formElements[i], 'mousedown', releaseForms, true);
2086                }
2087            }
2088        }
2089        //Prevent Links Events
2090        if (params.preventLinks) {
2091            var links = $$('a', _this.container);
2092            for (i = 0; i < links.length; i++) {
2093                unbind(links[i], 'click', preventClick);
2094            }
2095        }
2096    }
2097    /*==========================================
2098        Keyboard Control
2099    ============================================*/
2100    function handleKeyboardKeys(e) {
2101        var kc = e.keyCode || e.charCode;
2102        if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) return;
2103        if (kc === 37 || kc === 39 || kc === 38 || kc === 40) {
2104            var inView = false;
2105            //Check that swiper should be inside of visible area of window
2106            var swiperOffset = _this.h.getOffset(_this.container);
2107            var scrollLeft = _this.h.windowScroll().left;
2108            var scrollTop = _this.h.windowScroll().top;
2109            var windowWidth = _this.h.windowWidth();
2110            var windowHeight = _this.h.windowHeight();
2111            var swiperCoord = [
2112                [swiperOffset.left, swiperOffset.top],
2113                [swiperOffset.left + _this.width, swiperOffset.top],
2114                [swiperOffset.left, swiperOffset.top + _this.height],
2115                [swiperOffset.left + _this.width, swiperOffset.top + _this.height]
2116            ];
2117            for (var i = 0; i < swiperCoord.length; i++) {
2118                var point = swiperCoord[i];
2119                if (
2120                    point[0] >= scrollLeft && point[0] <= scrollLeft + windowWidth &&
2121                    point[1] >= scrollTop && point[1] <= scrollTop + windowHeight
2122                ) {
2123                    inView = true;
2124                }
2125
2126            }
2127            if (!inView) return;
2128        }
2129        if (isH) {
2130            if (kc === 37 || kc === 39) {
2131                if (e.preventDefault) e.preventDefault();
2132                else e.returnValue = false;
2133            }
2134            if (kc === 39) _this.swipeNext();
2135            if (kc === 37) _this.swipePrev();
2136        }
2137        else {
2138            if (kc === 38 || kc === 40) {
2139                if (e.preventDefault) e.preventDefault();
2140                else e.returnValue = false;
2141            }
2142            if (kc === 40) _this.swipeNext();
2143            if (kc === 38) _this.swipePrev();
2144        }
2145    }
2146
2147    _this.disableKeyboardControl = function () {
2148        params.keyboardControl = false;
2149        _this.h.removeEventListener(document, 'keydown', handleKeyboardKeys);
2150    };
2151
2152    _this.enableKeyboardControl = function () {
2153        params.keyboardControl = true;
2154        _this.h.addEventListener(document, 'keydown', handleKeyboardKeys);
2155    };
2156
2157    /*==========================================
2158        Mousewheel Control
2159    ============================================*/
2160    var lastScrollTime = (new Date()).getTime();
2161    function handleMousewheel(e) {
2162        var we = _this._wheelEvent;
2163        var delta = 0;
2164
2165        //Opera & IE
2166        if (e.detail) delta = -e.detail;
2167        //WebKits
2168        else if (we === 'mousewheel') {
2169            if (params.mousewheelControlForceToAxis) {
2170                if (isH) {
2171                    if (Math.abs(e.wheelDeltaX) > Math.abs(e.wheelDeltaY)) delta = e.wheelDeltaX;
2172                    else return;
2173                }
2174                else {
2175                    if (Math.abs(e.wheelDeltaY) > Math.abs(e.wheelDeltaX)) delta = e.wheelDeltaY;
2176                    else return;
2177                }
2178            }
2179            else {
2180                delta = e.wheelDelta;
2181            }
2182        }
2183        //Old FireFox
2184        else if (we === 'DOMMouseScroll') delta = -e.detail;
2185        //New FireFox
2186        else if (we === 'wheel') {
2187            if (params.mousewheelControlForceToAxis) {
2188                if (isH) {
2189                    if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) delta = -e.deltaX;
2190                    else return;
2191                }
2192                else {
2193                    if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) delta = -e.deltaY;
2194                    else return;
2195                }
2196            }
2197            else {
2198                delta = Math.abs(e.deltaX) > Math.abs(e.deltaY) ? - e.deltaX : - e.deltaY;
2199            }
2200        }
2201
2202        if (!params.freeMode) {
2203            if ((new Date()).getTime() - lastScrollTime > 60) {
2204                if (delta < 0) _this.swipeNext();
2205                else _this.swipePrev();
2206            }
2207            lastScrollTime = (new Date()).getTime();
2208
2209        }
2210        else {
2211            //Freemode or scrollContainer:
2212            var position = _this.getWrapperTranslate() + delta;
2213
2214            if (position > 0) position = 0;
2215            if (position < -maxWrapperPosition()) position = -maxWrapperPosition();
2216
2217            _this.setWrapperTransition(0);
2218            _this.setWrapperTranslate(position);
2219            _this.updateActiveSlide(position);
2220
2221            // Return page scroll on edge positions
2222            if (position === 0 || position === -maxWrapperPosition()) return;
2223        }
2224        if (params.autoplay) _this.stopAutoplay(true);
2225
2226        if (e.preventDefault) e.preventDefault();
2227        else e.returnValue = false;
2228        return false;
2229    }
2230    _this.disableMousewheelControl = function () {
2231        if (!_this._wheelEvent) return false;
2232        params.mousewheelControl = false;
2233        _this.h.removeEventListener(_this.container, _this._wheelEvent, handleMousewheel);
2234        return true;
2235    };
2236
2237    _this.enableMousewheelControl = function () {
2238        if (!_this._wheelEvent) return false;
2239        params.mousewheelControl = true;
2240        _this.h.addEventListener(_this.container, _this._wheelEvent, handleMousewheel);
2241        return true;
2242    };
2243
2244    /*=========================
2245      Grab Cursor
2246      ===========================*/
2247    if (params.grabCursor) {
2248        var containerStyle = _this.container.style;
2249        containerStyle.cursor = 'move';
2250        containerStyle.cursor = 'grab';
2251        containerStyle.cursor = '-moz-grab';
2252        containerStyle.cursor = '-webkit-grab';
2253    }
2254
2255    /*=========================
2256      Slides Events Handlers
2257      ===========================*/
2258
2259    _this.allowSlideClick = true;
2260    function slideClick(event) {
2261        if (_this.allowSlideClick) {
2262            setClickedSlide(event);
2263            _this.fireCallback(params.onSlideClick, _this, event);
2264        }
2265    }
2266
2267    function slideTouch(event) {
2268        setClickedSlide(event);
2269        _this.fireCallback(params.onSlideTouch, _this, event);
2270    }
2271
2272    function setClickedSlide(event) {
2273
2274        // IE 6-8 support
2275        if (!event.currentTarget) {
2276            var element = event.srcElement;
2277            do {
2278                if (element.className.indexOf(params.slideClass) > -1) {
2279                    break;
2280                }
2281                element = element.parentNode;
2282            } while (element);
2283            _this.clickedSlide = element;
2284        }
2285        else {
2286            _this.clickedSlide = event.currentTarget;
2287        }
2288
2289        _this.clickedSlideIndex     = _this.slides.indexOf(_this.clickedSlide);
2290        _this.clickedSlideLoopIndex = _this.clickedSlideIndex - (_this.loopedSlides || 0);
2291    }
2292
2293    _this.allowLinks = true;
2294    function preventClick(e) {
2295        if (!_this.allowLinks) {
2296            if (e.preventDefault) e.preventDefault();
2297            else e.returnValue = false;
2298            if (params.preventLin
2298ksPropagation && 'stopPropagation' in e) {
2299                e.stopPropagation();
2300            }
2301            return false;
2302        }
2303    }
2304    function releaseForms(e) {
2305        if (e.stopPropagation) e.stopPropagation();
2306        else e.returnValue = false;
2307        return false;
2308
2309    }
2310
2311    /*==================================================
2312        Event Handlers
2313    ====================================================*/
2314    var isTouchEvent = false;
2315    var allowThresholdMove;
2316    var allowMomentumBounce = true;
2317    function onTouchStart(event) {
2318        if (params.preventLinks) _this.allowLinks = true;
2319        //Exit if slider is already was touched
2320        if (_this.isTouched || params.onlyExternal) {
2321            return false;
2322        }
2323
2324        // Blur active elements
2325        var eventTarget = event.target || event.srcElement;
2326        if (document.activeElement && document.activeElement !== document.body) {
2327            if (document.activeElement !== eventTarget) document.activeElement.blur();
2328        }
2329
2330        // Form tag names
2331        var formTagNames = ('input select textarea').split(' ');
2332
2333        // Check for no swiping
2334        if (params.noSwiping && (eventTarget) && noSwipingSlide(eventTarget)) return false;
2335        allowMomentumBounce = false;
2336        //Check For Nested SwiftSwipers
2337        _this.isTouched = true;
2338        isTouchEvent = event.type === 'touchstart';
2339
2340        // prevent user enter with right and the swiper move (needs isTouchEvent)
2341        if (!isTouchEvent && 'which' in event && event.which === 3) {
2342            _this.isTouched = false;
2343            return false;
2344        }
2345
2346        if (!isTouchEvent || event.targetTouches.length === 1) {
2347            _this.callPlugins('onTouchStartBegin');
2348            if (!isTouchEvent && !_this.isAndroid && formTagNames.indexOf(eventTarget.tagName.toLowerCase()) < 0) {
2349
2350                if (event.preventDefault) event.preventDefault();
2351                else event.returnValue = false;
2352            }
2353
2354            var pageX = isTouchEvent ? event.targetTouches[0].pageX : (event.pageX || event.clientX);
2355            var pageY = isTouchEvent ? event.targetTouches[0].pageY : (event.pageY || event.clientY);
2356
2357            //Start Touches to check the scrolling
2358            _this.touches.startX = _this.touches.currentX = pageX;
2359            _this.touches.startY = _this.touches.currentY = pageY;
2360
2361            _this.touches.start = _this.touches.current = isH ? pageX : pageY;
2362
2363            //Set Transition Time to 0
2364            _this.setWrapperTransition(0);
2365
2366            //Get Start Translate Position
2367            _this.positions.start = _this.positions.current = _this.getWrapperTranslate();
2368
2369            //Set Transform
2370            _this.setWrapperTranslate(_this.positions.start);
2371
2372            //TouchStartTime
2373            _this.times.start = (new Date()).getTime();
2374
2375            //Unset Scrolling
2376            isScrolling = undefined;
2377
2378            //Set Treshold
2379            if (params.moveStartThreshold > 0) {
2380                allowThresholdMove = false;
2381            }
2382
2383            //CallBack
2384            if (params.onTouchStart) _this.fireCallback(params.onTouchStart, _this, event);
2385            _this.callPlugins('onTouchStartEnd');
2386
2387        }
2388    }
2389    var velocityPrevPosition, velocityPrevTime;
2390    function onTouchMove(event) {
2391        // If slider is not touched - exit
2392        if (!_this.isTouched || params.onlyExternal) return;
2393        if (isTouchEvent && event.type === 'mousemove') return;
2394
2395        var pageX = isTouchEvent ? event.targetTouches[0].pageX : (event.pageX || event.clientX);
2396        var pageY = isTouchEvent ? event.targetTouches[0].pageY : (event.pageY || event.clientY);
2397
2398        //check for scrolling
2399        if (typeof isScrolling === 'undefined' && isH) {
2400            isScrolling = !!(isScrolling || Math.abs(pageY - _this.touches.startY) > Math.abs(pageX - _this.touches.startX));
2401        }
2402        if (typeof isScrolling === 'undefined' && !isH) {
2403            isScrolling = !!(isScrolling || Math.abs(pageY - _this.touches.startY) < Math.abs(pageX - _this.touches.startX));
2404        }
2405        if (isScrolling) {
2406            _this.isTouched = false;
2407            return;
2408        }
2409
2410        // One way swipes
2411        if (isH) {
2412            if ((!params.swipeToNext && pageX < _this.touches.startX) || ((!params.swipeToPrev && pageX > _this.touches.startX))) {
2413                return;
2414            }
2415        }
2416        else {
2417            if ((!params.swipeToNext && pageY < _this.touches.startY) || ((!params.swipeToPrev && pageY > _this.touches.startY))) {
2418                return;
2419            }
2420        }
2421
2422        //Check For Nested SwiftSwipers
2423        if (event.assignedToSwiftSwiper) {
2424            _this.isTouched = false;
2425            return;
2426        }
2427        event.assignedToSwiftSwiper = true;
2428
2429        //Block inner links
2430        if (params.preventLinks) {
2431            _this.allowLinks = false;
2432        }
2433        if (params.onSlideClick) {
2434            _this.allowSlideClick = false;
2435        }
2436
2437        //Stop AutoPlay if exist
2438        if (params.autoplay) {
2439            _this.stopAutoplay(true);
2440        }
2441        if (!isTouchEvent || event.touches.length === 1) {
2442
2443            //Moved Flag
2444            if (!_this.isMoved) {
2445                _this.callPlugins('onTouchMoveStart');
2446
2447                if (params.loop) {
2448                    _this.fixLoop();
2449                    _this.positions.start = _this.getWrapperTranslate();
2450                }
2451                if (params.onTouchMoveStart) _this.fireCallback(params.onTouchMoveStart, _this);
2452            }
2453            _this.isMoved = true;
2454
2455            // cancel event
2456            if (event.preventDefault) event.preventDefault();
2457            else event.returnValue = false;
2458
2459            _this.touches.current = isH ? pageX : pageY;
2460
2461            _this.positions.current = (_this.touches.current - _this.touches.start) * params.touchRatio + _this.positions.start;
2462
2463            //Resistance Callbacks
2464            if (_this.positions.current > 0 && params.onResistanceBefore) {
2465                _this.fireCallback(params.onResistanceBefore, _this, _this.positions.current);
2466            }
2467            if (_this.positions.current < -maxWrapperPosition() && params.onResistanceAfter) {
2468                _this.fireCallback(params.onResistanceAfter, _this, Math.abs(_this.positions.current + maxWrapperPosition()));
2469            }
2470            //Resistance
2471            if (params.resistance && params.resistance !== '100%') {
2472                var resistance;
2473                //Resistance for Negative-Back sliding
2474                if (_this.positions.current > 0) {
2475                    resistance = 1 - _this.positions.current / containerSize / 2;
2476                    if (resistance < 0.5)
2477                        _this.positions.current = (containerSize / 2);
2478                    else
2479                        _this.positions.current = _this.positions.current * resistance;
2480                }
2481                //Resistance for After-End Sliding
2482                if (_this.positions.current < -maxWrapperPosition()) {
2483
2484                    var diff = (_this.touches.current - _this.touches.start) * params.touchRatio + (maxWrapperPosition() + _this.positions.start);
2485                    resistance = (containerSize + diff) / (containerSize);
2486                    var newPos = _this.positions.current - diff * (1 - resistance) / 2;
2487                    var stopPos = -maxWrapperPosition() - containerSize / 2;
2488
2489                    if (newPos < stopPos || resistance <= 0)
2490                        _this.positions.current = stopPos;
2491                    else
2492                        _this.positions.current = newPos;
2493                }
2494            }
2495            if (params.resistance && params.resistance === '100%') {
2496                //Resistance for Negative-Back sliding
2497                if (_this.positions.current > 0 && !(params.freeMode && !params.freeModeFluid)) {
2498                    _this.positions.current = 0;
2499                }
2500                //Resistance for After-End Sliding
2501                if (_this.positions.current < -maxWrapperPosition() && !(params.freeMode && !params.freeModeFluid)) {
2502                    _this.positions.current = -maxWrapperPosition();
2503                }
2504            }
2505            //Move Slides
2506            if (!params.followFinger) return;
2507
2508            if (!params.moveStartThreshold) {
2509                _this.setWrapperTranslate(_this.positions.current);
2510            }
2511            else {
2512                if (Math.abs(_this.touches.current - _this.touches.start) > params.moveStartThreshold || allowThresholdMove) {
2513                    if (!allowThresholdMove) {
2514                        allowThresholdMove = true;
2515                        _this.touches.start = _this.touches.current;
2516                        return;
2517                    }
2518                    _this.setWrapperTranslate(_this.positions.current);
2519                }
2520                else {
2521                    _this.positions.current = _this.positions.start;
2522                }
2523            }
2524
2525            if (params.freeMode || params.watchActiveIndex) {
2526                _this.updateActiveSlide(_this.positions.current);
2527            }
2528
2529            //Grab Cursor
2530            if (params.grabCursor) {
2531                _this.container.style.cursor = 'move';
2532                _this.container.style.cursor = 'grabbing';
2533                _this.container.style.cursor = '-moz-grabbin';
2534                _this.container.style.cursor = '-webkit-grabbing';
2535            }
2536            //Velocity
2537            if (!velocityPrevPosition) velocityPrevPosition = _this.touches.current;
2538            if (!velocityPrevTime) velocityPrevTime = (new Date()).getTime();
2539            _this.velocity = (_this.touches.current - velocityPrevPosition) / ((new Date()).getTime() - velocityPrevTime) / 2;
2540            if (Math.abs(_this.touches.current - velocityPrevPosition) < 2) _this.velocity = 0;
2541            velocityPrevPosition = _this.touches.current;
2542            velocityPrevTime = (new Date()).getTime();
2543            //Callbacks
2544            _this.callPlugins('onTouchMoveEnd');
2545            if (params.onTouchMove) _this.fireCallback(params.onTouchMove, _this, event);
2546
2547            return false;
2548        }
2549    }
2550    function onTouchEnd(event) {
2551        //Check For scrolling
2552        if (isScrolling) {
2553            _this.swipeReset();
2554        }
2555        // If slider is not touched exit
2556        if (params.onlyExternal || !_this.isTouched) return;
2557        _this.isTouched = false;
2558
2559        //Return Grab Cursor
2560        if (params.grabCursor) {
2561            _this.container.style.cursor = 'move';
2562            _this.container.style.cursor = 'grab';
2563            _this.container.style.cursor = '-moz-grab';
2564            _this.container.style.cursor = '-webkit-grab';
2565        }
2566
2567        //Check for Current Position
2568        if (!_this.positions.current && _this.positions.current !== 0) {
2569            _this.positions.current = _this.positions.start;
2570        }
2571
2572        //For case if slider touched but not moved
2573        if (params.followFinger) {
2574            _this.setWrapperTranslate(_this.positions.current);
2575        }
2576
2577        // TouchEndTime
2578        _this.times.end = (new Date()).getTime();
2579
2580        //Difference
2581        _this.touches.diff = _this.touches.current - _this.touches.start;
2582        _this.touches.abs = Math.abs(_this.touches.diff);
2583
2584        _this.positions.diff = _this.positions.current - _this.positions.start;
2585        _this.positions.abs = Math.abs(_this.positions.diff);
2586
2587        var diff = _this.positions.diff;
2588        var diffAbs = _this.positions.abs;
2589        var timeDiff = _this.times.end - _this.times.start;
2590
2591        if (diffAbs < 5 && (timeDiff) < 300 && _this.allowLinks === false) {
2592            if (!params.freeMode && diffAbs !== 0) _this.swipeReset();
2593            //Release inner links
2594            if (params.preventLinks) {
2595                _this.allowLinks = true;
2596            }
2597            if (params.onSlideClick) {
2598                _this.allowSlideClick = true;
2599            }
2600        }
2601
2602        setTimeout(function () {
2603            //Release inner links
2604            if (typeof _this === 'undefined' || _this === null) return;
2605            if (params.preventLinks) {
2606                _this.allowLinks = true;
2607            }
2608            if (params.onSlideClick) {
2609                _this.allowSlideClick = true;
2610            }
2611        }, 100);
2612
2613        var maxPosition = maxWrapperPosition();
2614
2615        //Not moved or Prevent Negative Back Sliding/After-End Sliding
2616        if (!_this.isMoved && params.freeMode) {
2617            _this.isMoved = false;
2618            if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event);
2619            _this.callPlugins('onTouchEnd');
2620            return;
2621        }
2622        if (!_this.isMoved || _this.positions.current > 0 || _this.positions.current < -maxPosition) {
2623            _this.swipeReset();
2624            if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event);
2625            _this.callPlugins('onTouchEnd');
2626            return;
2627        }
2628
2629        _this.isMoved = false;
2630
2631        //Free Mode
2632        if (params.freeMode) {
2633            if (params.freeModeFluid) {
2634                var momentumDuration = 1000 * params.momentumRatio;
2635                var momentumDistance = _this.velocity * momentumDuration;
2636                var newPosition = _this.positions.current + momentumDistance;
2637                var doBounce = false;
2638                var afterBouncePosition;
2639                var bounceAmount = Math.abs(_this.velocity) * 20 * params.momentumBounceRatio;
2640                if (newPosition < -maxPosition) {
2641                    if (params.momentumBounce && _this.support.transitions) {
2642                        if (newPosition + maxPosition < -bounceAmount) newPosition = -maxPosition - bounceAmount;
2643                        afterBouncePosition = -maxPosition;
2644                        doBounce = true;
2645                        allowMomentumBounce = true;
2646                    }
2647                    else newPosition = -maxPosition;
2648                }
2649                if (newPosition > 0) {
2650                    if (params.momentumBounce && _this.support.transitions) {
2651                        if (newPosition > bounceAmount) newPosition = bounceAmount;
2652                        afterBouncePosition = 0;
2653                        doBounce = true;
2654                        allowMomentumBounce = true;
2655                    }
2656                    else newPosition = 0;
2657                }
2658                //Fix duration
2659                if (_this.velocity !== 0) momentumDuration = Math.abs((newPosition - _this.positions.current) / _this.velocity);
2660
2661                _this.setWrapperTranslate(newPosition);
2662
2663                _this.setWrapperTransition(momentumDuration);
2664
2665                if (params.momentumBounce && doBounce) {
2666                    _this.wrapperTransitionEnd(function () {
2667                        if (!allowMomentumBounce) return;
2668                        if (params.onMomentumBounce) _this.fireCallback(params.onMomentumBounce, _this);
2669                        _this.callPlugins('onMomentumBounce');
2670
2671                        _this.setWrapperTranslate(afterBouncePosition);
2672                        _this.setWrapperTransition(300);
2673                    });
2674                }
2675
2676                _this.updateActiveSlide(newPosition);
2677            }
2678            if (!params.freeModeFluid || timeDiff >= 300) _this.updateActiveSlide(_this.positions.current);
2679
2680            if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event);
2681            _this.callPlugins('onTouchEnd');
2682            return;
2683        }
2684
2685        //Direction
2686        direction = diff < 0 ? 'toNext' : 'toPrev';
2687
2688        //Short Touches
2689        if (direction === 'toNext' && (timeDiff <= 300)) {
2690            if (diffAbs < 30 || !params.shortSwipes) _this.swipeReset();
2691            else _this.swipeNext(true, true);
2692        }
2693
2694        if (direction === 'toPrev' && (timeDiff <= 300)) {
2695            if (diffAbs < 30 || !params.shortSwipes) _this.swipeReset();
2696            else _this.swipePrev(true, true);
2697        }
2698
2699        //Long Touches
2700        var targetSlideSize = 0;
2701        if (params.slidesPerView === 'auto') {
2702            //Define current slide's width
2703            var currentPosition = Math.abs(_this.getWrapperTranslate());
2704            var slidesOffset = 0;
2705            var _slideSize;
2706            for (var i = 0; i < _this.slides.length; i++) {
2707                _slideSize = isH ? _this.slides[i].getWidth(true, params.roundLengths) : _this.slides[i].getHeight(true, params.roundLengths);
2708                slidesOffset += _slideSize;
2709                if (slidesOffset > currentPosition) {
2710                    targetSlideSize = _slideSize;
2711                    break;
2712                }
2713            }
2714            if (targetSlideSize > containerSize) targetSlideSize = containerSize;
2715        }
2716        else {
2717            targetSlideSize = slideSize * params.slidesPerView;
2718        }
2719        if (direction === 'toNext' && (timeDiff > 300)) {
2720            if (diffAbs >= targetSlideSize * params.longSwipesRatio) {
2721                _this.swipeNext(true, true);
2722            }
2723            else {
2724                _this.swipeReset();
2725            }
2726        }
2727        if (direction === 'toPrev' && (timeDiff > 300)) {
2728            if (diffAbs >= targetSlideSize * params.longSwipesRatio) {
2729                _this.swipePrev(true, true);
2730            }
2731            else {
2732                _this.swipeReset();
2733            }
2734        }
2735        if (params.onTouchEnd) _this.fireCallback(params.onTouchEnd, _this, event);
2736        _this.callPlugins('onTouchEnd');
2737    }
2738
2739
2740    /*==================================================
2741        noSwiping Bubble Check by Isaac Strack
2742    ====================================================*/
2743    function hasClass(el, classname) {
2744        return el && el.getAttribute('class') && el.getAttribute('class').indexOf(classname) > -1;
2745    }
2746    function noSwipingSlide(el) {
2747        /*This function is specifically designed to check the parent elements for the noSwiping class, up to the wrapper.
2748        We need to check parents because while onTouchStart bubbles, _this.isTouched is checked in onTouchStart, which stops the bubbling.
2749        So, if a text box, for example, is the initial target, and the parent slide container has the noSwiping class, the _this.isTouched
2750        check will never find it, and what was supposed to be noSwiping is able to be swiped.
2751        This function will iterate up and check for the noSwiping class in parents, up through the wrapperClass.*/
2752
2753        // First we create a truthy variable, which is that swiping is allowd (noSwiping = false)
2754        var noSwiping = false;
2755
2756        // Now we iterate up (parentElements) until we reach the node with the wrapperClass.
2757        do {
2758
2759            // Each time, we check to see if there's a 'swiper-no-swiping' class (noSwipingClass).
2760            if (hasClass(el, params.noSwipingClass))
2761            {
2762                noSwiping = true; // If there is, we set noSwiping = true;
2763            }
2764
2765            el = el.parentElement;  // now we iterate up (parent node)
2766
2767        } while (!noSwiping && el.parentElement && !hasClass(el, params.wrapperClass)); // also include el.parentElement truthy, just in case.
2768
2769        // because we didn't check the wrapper itself, we do so now, if noSwiping is false:
2770        if (!noSwiping && hasClass(el, params.wrapperClass) && hasClass(el, params.noSwipingClass))
2771            noSwiping = true; // if the wrapper has the noSwipingClass, we set noSwiping = true;
2772
2773        return noSwiping;
2774    }
2775
2776    function addClassToHtmlString(klass, outerHtml) {
2777        var par = document.createElement('div');
2778        var child;
2779
2780        par.innerHTML = outerHtml;
2781        child = par.firstChild;
2782        child.className += ' ' + klass;
2783
2784        return child.outerHTML;
2785    }
2786
2787
2788    /*==================================================
2789        Swipe Functions
2790    ====================================================*/
2791    _this.swipeNext = function (runCallbacks, internal) {
2792        if (typeof runCallbacks === 'undefined') runCallbacks = true;
2793        if (!internal && params.loop) _this.fixLoop();
2794        if (!internal && params.autoplay) _this.stopAutoplay(true);
2795        _this.callPlugins('onSwipeNext');
2796        var currentPosition = _this.getWrapperTranslate().toFixed(2);
2797        var newPosition = currentPosition;
2798        if (params.slidesPerView === 'auto') {
2799            for (var i = 0; i < _this.snapGrid.length; i++) {
2800                if (-currentPosition >= _this.snapGrid[i].toFixed(2) && -currentPosition < _this.snapGrid[i + 1].toFixed(2)) {
2801                    newPosition = -_this.snapGrid[i + 1];
2802                    break;
2803                }
2804            }
2805        }
2806        else {
2807            var groupSize = slideSize * params.slidesPerGroup;
2808            newPosition = -(Math.floor(Math.abs(currentPosition) / Math.floor(groupSize)) * groupSize + groupSize);
2809        }
2810        if (newPosition < -maxWrapperPosition()) {
2811            newPosition = -maxWrapperPosition();
2812        }
2813        if (newPosition === parseInt(currentPosition, 10)) {
2814            var ai = jQuery( _this.container );
2815            if ( ai.data( "slider-type" ) === "curtain" && ai.data( "continue" ) ) {
2816                SWIFTSLIDER.curtainAdvance( ai );
2817            } else {
2818                return false;
2819            }
2820        }
2821        swipeToPosition(newPosition, 'next', {runCallbacks: runCallbacks});
2822        return true;
2823    };
2824    _this.swipePrev = function (runCallbacks, internal) {
2825        if (typeof runCallbacks === 'undefined') runCallbacks = true;
2826        if (!internal && params.loop) _this.fixLoop();
2827        if (!internal && params.autoplay) _this.stopAutoplay(true);
2828        _this.callPlugins('onSwipePrev');
2829
2830        var ai = jQuery( _this.container );
2831        if ( ai.data( "slider-type" ) === "curtain" && SWIFTSLIDER.curtainAnimating ) {
2832            return false;
2833        }
2834
2835        var currentPosition = Math.ceil(_this.getWrapperTranslate());
2836        var newPosition;
2837        if (params.slidesPerView === 'auto') {
2838            newPosition = 0;
2839            for (var i = 1; i < _this.snapGrid.length; i++) {
2840                if (-currentPosition === _this.snapGrid[i]) {
2841                    newPosition = -_this.snapGrid[i - 1];
2842                    break;
2843                }
2844                if (-currentPosition > _this.snapGrid[i] && -currentPosition < _this.snapGrid[i + 1]) {
2845                    newPosition = -_this.snapGrid[i];
2846                    break;
2847                }
2848            }
2849        }
2850        else {
2851            var groupSize = slideSize * params.slidesPerGroup;
2852            newPosition = -(Math.ceil(-currentPosition / groupSize) - 1) * groupSize;
2853        }
2854
2855        if (newPosition > 0) newPosition = 0;
2856
2857        if (newPosition === currentPosition) return false;
2858        swipeToPosition(newPosition, 'prev', {runCallbacks: runCallbacks});
2859        return true;
2860
2861    };
2862    _this.swipeReset = function (runCallbacks) {
2863        if (typeof runCallbacks === 'undefined') runCallbacks = true;
2864        _this.callPlugins('onSwipeReset');
2865        var currentPosition = _this.getWrapperTranslate();
2866        var groupSize = slideSize * params.slidesPerGroup;
2867        var newPosition;
2868        var maxPosition = -maxWrapperPosition();
2869        if (params.slidesPerView === 'auto') {
2870            newPosition = 0;
2871            for (var i = 0; i < _this.snapGrid.length; i++) {
2872                if (-currentPosition === _this.snapGrid[i]) return;
2873                if (-currentPosition >= _this.snapGrid[i] && -currentPosition < _this.snapGrid[i + 1]) {
2874                    if (_this.positions.diff > 0) newPosition = -_this.snapGrid[i + 1];
2875                    else newPosition = -_this.snapGrid[i];
2876                    break;
2877                }
2878            }
2879            if (-currentPosition >= _this.snapGrid[_this.snapGrid.length - 1]) newPosition = -_this.snapGrid[_this.snapGrid.length - 1];
2880            if (currentPosition <= -maxWrapperPosition()) newPosition = -maxWrapperPosition();
2881        }
2882        else {
2883            newPosition = currentPosition < 0 ? Math.round(currentPosition / groupSize) * groupSize : 0;
2884            if (currentPosition <= -maxWrapperPosition()) newPosition = -maxWrapperPosition();
2885        }
2886        if (params.scrollContainer)  {
2887            newPosition = currentPosition < 0 ? currentPosition : 0;
2888        }
2889        if (newPosition < -maxWrapperPosition()) {
2890            newPosition = -maxWrapperPosition();
2891        }
2892        if (params.scrollContainer && (containerSize > slideSize)) {
2893            newPosition = 0;
2894        }
2895
2896        if (newPosition === currentPosition) return false;
2897
2898        swipeToPosition(newPosition, 'reset', {runCallbacks: runCallbacks});
2899        return true;
2900    };
2901
2902    _this.swipeTo = function (index, speed, runCallbacks) {
2903        index = parseInt(index, 10);
2904        _this.callPlugins('onSwipeTo', {index: index, speed: speed});
2905        if (params.loop) index = index + _this.loopedSlides;
2906        var currentPosition = _this.getWrapperTranslate();
2907        if (index > (_this.slides.length - 1) || index < 0) return;
2908        var newPosition;
2909        if (params.slidesPerView === 'auto') {
2910            newPosition = -_this.slidesGrid[index];
2911        }
2912        else {
2913            newPosition = -index * slideSize;
2914        }
2915        if (newPosition < - maxWrapperPosition()) {
2916            newPosition = - maxWrapperPosition();
2917        }
2918
2919        if (newPosition === currentPosition) return false;
2920
2921        if (typeof runCallbacks === 'undefined') runCallbacks = true;
2922        swipeToPosition(newPosition, 'to', {index: index, speed: speed, runCallbacks: runCallbacks});
2923        return true;
2924    };
2925
2926    function swipeToPosition(newPosition, action, toOptions) {
2927        var speed = (action === 'to' && toOptions.speed >= 0) ? toOptions.speed : params.speed;
2928        var timeOld = + new Date();
2929
2930        function anim() {
2931            var timeNew = + new Date();
2932            var time = timeNew - timeOld;
2933            currentPosition += animationStep * time / (1000 / 60);
2934            condition = direction === 'toNext' ? currentPosition > newPosition : currentPosition < newPosition;
2935            if (condition) {
2936                _this.setWrapperTranslate(Math.ceil(currentPosition));
2937                _this._DOMAnimating = true;
2938                window.setTimeout(function () {
2939                    anim();
2940                }, 1000 / 60);
2941            }
2942            else {
2943                if (params.onSlideChangeEnd) {
2944                    if (action === 'to') {
2945                        if (toOptions.runCallbacks === true) _this.fireCallback(params.onSlideChangeEnd, _this, direction);
2946                    }
2947                    else {
2948                        _this.fireCallback(params.onSlideChangeEnd, _this, direction);
2949                    }
2950
2951                }
2952                _this.setWrapperTranslate(newPosition);
2953                _this._DOMAnimating = false;
2954            }
2955        }
2956
2957        if (_this.support.transitions || !params.DOMAnimation) {
2958            _this.setWrapperTranslate(newPosition);
2959            _this.setWrapperTransition(speed);
2960        }
2961        else {
2962            //Try the DOM animation
2963            var currentPosition = _this.getWrapperTranslate();
2964            var animationStep = Math.ceil((newPosition - currentPosition) / speed * (1000 / 60));
2965            var direction = currentPosition > newPosition ? 'toNext' : 'toPrev';
2966            var condition = direction === 'toNext' ? currentPosition > newPosition : currentPosition < newPosition;
2967            if (_this._DOMAnimating) return;
2968
2969            anim();
2970        }
2971
2972        //Update Active Slide Index
2973        _this.updateActiveSlide(newPosition);
2974
2975        //Callbacks
2976        if (params.onSlideNext && action === 'next' && toOptions.runCallbacks === true) {
2977            _this.fireCallback(params.onSlideNext, _this, newPosition);
2978        }
2979        if (params.onSlidePrev && action === 'prev' && toOptions.runCallbacks === true) {
2980            _this.fireCallback(params.onSlidePrev, _this, newPosition);
2981        }
2982        //'Reset' Callback
2983        if (params.onSlideReset && action === 'reset' && toOptions.runCallbacks === true) {
2984            _this.fireCallback(params.onSlideReset, _this, newPosition);
2985        }
2986
2987        //'Next', 'Prev' and 'To' Callbacks
2988        if ((action === 'next' || action === 'prev' || action === 'to') && toOptions.runCallbacks === true)
2989            slideChangeCallbacks(action);
2990    }
2991    /*==================================================
2992        Transition Callbacks
2993    ====================================================*/
2994    //Prevent Multiple Callbacks
2995    _this._queueStartCallbacks = false;
2996    _this._queueEndCallbacks = false;
2997    function slideChangeCallbacks(direction) {
2998        //Transition Start Callback
2999        _this.callPlugins('onSlideChangeStart');
3000        if (params.onSlideChangeStart) {
3001            if (params.queueStartCallbacks && _this.support.transitions) {
3002                if (_this._queueStartCallbacks) return;
3003                _this._queueStartCallbacks = true;
3004                _this.fireCallback(params.onSlideChangeStart, _this, direction);
3005                _this.wrapperTransitionEnd(function () {
3006                    _this._queueStartCallbacks = false;
3007                });
3008            }
3009            else _this.fireCallback(params.onSlideChangeStart, _this, direction);
3010        }
3011        // Transition End Callback
3012        if (params.onSlideChangeEnd) {
3013            if (_this.support.transitions) {
3014                if (params.queueEndCallbacks) {
3015                    if (_this._queueEndCallbacks) return;
3016                    _this._queueEndCallbacks = true;
3017                    if ( params.transition === "fade" ) {
3018                        setTimeout(function() {
3019                             _this.fireCallback(params.onSlideChangeEnd, _this, direction);
3020                        }, 100);
3021                    } else {
3022                        _this.wrapperTransitionEnd(function (swiper) {
3023                            _this.fireCallback(params.onSlideChangeEnd, _this, direction);
3024                        });
3025                    }
3026                }
3027                else {
3028                    if ( params.transition === "fade" ) {
3029                        setTimeout(function() {
3030                             _this.fireCallback(params.onSlideChangeEnd, _this, direction);
3031                        }, 100);
3032                    } else {
3033                        _this.wrapperTransitionEnd(function (swiper) {
3034                            _this.fireCallback(params.onSlideChangeEnd, _this, direction);
3035                        });
3036                    }
3037                }
3038            }
3039            else {
3040                if (!params.DOMAnimation) {
3041                    setTimeout(function () {
3042                        _this.fireCallback(params.onSlideChangeEnd, _this, direction);
3043                    }, 10);
3044                }
3045            }
3046        }
3047    }
3048
3049    /*==================================================
3050        Update Active Slide Index
3051    ====================================================*/
3052    _this.updateActiveSlide = function (position) {
3053        if (!_this.initialized) return;
3054        if (_this.slides.length === 0) return;
3055        _this.previousIndex = _this.activeIndex;
3056        if (typeof position === 'undefined') position = _this.getWrapperTranslate();
3057        if (position > 0) position = 0;
3058        var i;
3059        if (params.slidesPerView === 'auto') {
3060            var slidesOffset = 0;
3061            _this.activeIndex = _this.slidesGrid.indexOf(-position);
3062            if (_this.activeIndex < 0) {
3063                for (i = 0; i < _this.slidesGrid.length - 1; i++) {
3064                    if (-position > _this.slidesGrid[i] && -position < _this.slidesGrid[i + 1]) {
3065                        break;
3066                    }
3067                }
3068                var leftDistance = Math.abs(_this.slidesGrid[i] + position);
3069                var rightDistance = Math.abs(_this.slidesGrid[i + 1] + position);
3070                if (leftDistance <= rightDistance) _this.activeIndex = i;
3071                else _this.activeIndex = i + 1;
3072            }
3073        }
3074        else {
3075            _this.activeIndex = Math[params.visibilityFullFit ? 'ceil' : 'round'](-position / slideSize);
3076        }
3077
3078        if (_this.activeIndex === _this.slides.length) _this.activeIndex = _this.slides.length - 1;
3079        if (_this.activeIndex < 0) _this.activeIndex = 0;
3080
3081        // Check for slide
3082        if (!_this.slides[_this.activeIndex]) return;
3083
3084        // Calc Visible slides
3085        _this.calcVisibleSlides(position);
3086
3087        // Mark visible and active slides with additonal classes
3088        if (_this.support.classList) {
3089            var slide;
3090            for (i = 0; i < _this.slides.length; i++) {
3091                slide = _this.slides[i];
3092                slide.classList.remove(params.slideActiveClass);
3093                if (_this.visibleSlides.indexOf(slide) >= 0) {
3094                    slide.classList.add(params.slideVisibleClass);
3095                } else {
3096                    slide.classList.remove(params.slideVisibleClass);
3097                }
3098            }
3099            _this.slides[_this.activeIndex].classList.add(params.slideActiveClass);
3100        } else {
3101            var activeClassRegexp = new RegExp('\\s*' + params.slideActiveClass);
3102            var inViewClassRegexp = new RegExp('\\s*' + params.slideVisibleClass);
3103
3104            for (i = 0; i < _this.slides.length; i++) {
3105                _this.slides[i].className = _this.slides[i].className.replace(activeClassRegexp, '').replace(inViewClassRegexp, '');
3106                if (_this.visibleSlides.indexOf(_this.slides[i]) >= 0) {
3107                    _this.slides[i].className += ' ' + params.slideVisibleClass;
3108                }
3109            }
3110            _this.slides[_this.activeIndex].className += ' ' + params.slideActiveClass;
3111        }
3112
3113        //Update loop index
3114        if (params.loop) {
3115            var ls = _this.loopedSlides;
3116            _this.activeLoopIndex = _this.activeIndex - ls;
3117            if (_this.activeLoopIndex >= _this.slides.length - ls * 2) {
3118                _this.activeLoopIndex = _this.slides.length - ls * 2 - _this.activeLoopIndex;
3119            }
3120            if (_this.activeLoopIndex < 0) {
3121                _this.activeLoopIndex = _this.slides.length - ls * 2 + _this.activeLoopIndex;
3122            }
3123            if (_this.activeLoopIndex < 0) _this.activeLoopIndex = 0;
3124        }
3125        else {
3126            _this.activeLoopIndex = _this.activeIndex;
3127        }
3128        //Update Pagination
3129        if (params.pagination) {
3130            _this.updatePagination(position);
3131        }
3132    };
3133    /*==================================================
3134        Pagination
3135    ====================================================*/
3136    _this.createPagination = function (firstInit) {
3137        if (params.paginationClickable && _this.paginationButtons) {
3138            removePaginationEvents();
3139        }
3140        _this.paginationContainer = params.pagination.nodeType ? params.pagination : $$(params.pagination)[0];
3141        if (params.createPagination) {
3142            var paginationHTML = '';
3143            var numOfSlides = _this.slides.length;
3144            var numOfButtons = numOfSlides;
3145            if (params.loop) numOfButtons -= _this.loopedSlides * 2;
3146            for (var i = 0; i < numOfButtons; i++) {
3147                paginationHTML += '<' + params.paginationElement + ' class="' + params.paginationElementClass + '"></' + params.paginationElement + '>';
3148            }
3149            _this.paginationContainer.innerHTML = paginationHTML;
3150        }
3151        _this.paginationButtons = $$('.' + params.paginationElementClass, _this.paginationContainer);
3152        if (!firstInit) _this.updatePagination();
3153        _this.callPlugins('onCreatePagination');
3154        if (params.paginationClickable) {
3155            addPaginationEvents();
3156        }
3157    };
3158    function removePaginationEvents() {
3159        var pagers = _this.paginationButtons;
3160        if (pagers) {
3161            for (var i = 0; i < pagers.length; i++) {
3162                _this.h.removeEventListener(pagers[i], 'click', paginationClick);
3163            }
3164        }
3165    }
3166    function addPaginationEvents() {
3167        var pagers = _this.paginationButtons;
3168        if (pagers) {
3169            for (var i = 0; i < pagers.length; i++) {
3170                _this.h.addEventListener(pagers[i], 'click', paginationClick);
3171            }
3172        }
3173    }
3174    function paginationClick(e) {
3175        var index;
3176        var target = e.target || e.srcElement;
3177        var pagers = _this.paginationButtons;
3178        for (var i = 0; i < pagers.length; i++) {
3179            if (target === pagers[i]) index = i;
3180        }
3181        if (params.autoplay) _this.stopAutoplay(true);
3182        _this.swipeTo(index);
3183    }
3184    _this.updatePagination = function (position) {
3185        if (!params.pagination) return;
3186        if (_this.slides.length < 1) return;
3187        var activePagers = $$('.' + params.paginationActiveClass, _this.paginationContainer);
3188        if (!activePagers) return;
3189
3190        //Reset all Buttons' class to not active
3191        var pagers = _this.paginationButtons;
3192        if (pagers.length === 0) return;
3193        for (var i = 0; i < pagers.length; i++) {
3194            pagers[i].className = params.paginationElementClass;
3195        }
3196
3197        var indexOffset = params.loop ? _this.loopedSlides : 0;
3198        if (params.paginationAsRange) {
3199            if (!_this.visibleSlides) _this.calcVisibleSlides(position);
3200            //Get Visible Indexes
3201            var visibleIndexes = [];
3202            var j; // lopp index - avoid JSHint W004 / W038
3203            for (j = 0; j < _this.visibleSlides.length; j++) {
3204                var visIndex = _this.slides.indexOf(_this.visibleSlides[j]) - indexOffset;
3205
3206                if (params.loop && visIndex < 0) {
3207                    visIndex = _this.slides.length - _this.loopedSlides * 2 + visIndex;
3208                }
3209                if (params.loop && visIndex >= _this.slides.length - _this.loopedSlides * 2) {
3210                    visIndex = _this.slides.length - _this.loopedSlides * 2 - visIndex;
3211                    visIndex = Math.abs(visIndex);
3212                }
3213                visibleIndexes.push(visIndex);
3214            }
3215
3216            for (j = 0; j < visibleIndexes.length; j++) {
3217                if (pagers[visibleIndexes[j]]) pagers[visibleIndexes[j]].className += ' ' + params.paginationVisibleClass;
3218            }
3219
3220            if (params.loop) {
3221                if (pagers[_this.activeLoopIndex] !== undefined) {
3222                    pagers[_this.activeLoopIndex].className += ' ' + params.paginationActiveClass;
3223                }
3224            }
3225            else {
3226                if (pagers[_this.activeIndex]) pagers[_this.activeIndex].className += ' ' + params.paginationActiveClass;
3227            }
3228        }
3229        else {
3230            if (params.loop) {
3231                if (pagers[_this.activeLoopIndex]) pagers[_this.activeLoopIndex].className += ' ' + params.paginationActiveClass + ' ' + params.paginationVisibleClass;
3232            }
3233            else {
3234                if (pagers[_this.activeIndex]) pagers[_this.activeIndex].className += ' ' + params.paginationActiveClass + ' ' + params.paginationVisibleClass;
3235            }
3236        }
3237    };
3238    _this.calcVisibleSlides = function (position) {
3239        var visibleSlides = [];
3240        var _slideLeft = 0, _slideSize = 0, _slideRight = 0;
3241        if (isH && _this.wrapperLeft > 0) position = position + _this.wrapperLeft;
3242        if (!isH && _this.wrapperTop > 0) position = position + _this.wrapperTop;
3243
3244        for (var i = 0; i < _this.slides.length; i++) {
3245            _slideLeft += _slideSize;
3246            if (params.slidesPerView === 'auto')
3247                _slideSize  = isH ? _this.h.getWidth(_this.slides[i], true, params.roundLengths) : _this.h.getHeight(_this.slides[i], true, params.roundLengths);
3248            else _slideSize = slideSize;
3249
3250            _slideRight = _slideLeft + _slideSize;
3251            var isVisibile = false;
3252            if (params.visibilityFullFit) {
3253                if (_slideLeft >= -position && _slideRight <= -position + containerSize) isVisibile = true;
3254                if (_slideLeft <= -position && _slideRight >= -position + containerSize) isVisibile = true;
3255            }
3256            else {
3257                if (_slideRight > -position && _slideRight <= ((-position + containerSize))) isVisibile = true;
3258                if (_slideLeft >= -position && _slideLeft < ((-position + containerSize))) isVisibile = true;
3259                if (_slideLeft < -position && _slideRight > ((-position + containerSize))) isVisibile = true;
3260            }
3261
3262            if (isVisibile) visibleSlides.push(_this.slides[i]);
3263
3264        }
3265        if (visibleSlides.length === 0) visibleSlides = [_this.slides[_this.activeIndex]];
3266
3267        _this.visibleSlides = visibleSlides;
3268    };
3269
3270    /*==========================================
3271        Autoplay
3272    ============================================*/
3273    var autoplayTimeoutId, autoplayIntervalId;
3274    _this.startAutoplay = function () {
3275        var autoInterval = params.autoplay;
3276        var autoDelay = 2000;
3277
3278        setTimeout(function() {
3279            if (_this.support.transitions) {
3280                if (typeof autoplayTimeoutId !== 'undefined') return false;
3281                if (!params.autoplay) return;
3282                _this.callPlugins('onAutoplayStart');
3283                if (params.onAutoplayStart) _this.fireCallback(params.onAutoplayStart, _this);
3284                autoplay();
3285            }
3286            else {
3287                if (typeof autoplayIntervalId !== 'undefined') return false;
3288                if (!params.autoplay) return;
3289                _this.callPlugins('onAutoplayStart');
3290                if (params.onAutoplayStart) _this.fireCallback(params.onAutoplayStart, _this);
3291                autoplayIntervalId = setInterval(function () {
3292                    if (params.loop) {
3293                        _this.fixLoop();
3294                        _this.swipeNext(true, true);
3295                    }
3296                    else if (!_this.swipeNext(true, true)) {
3297                        if (!params.autoplayStopOnLast) _this.swipeTo(0);
3298                        else {
3299                            clearInterval(autoplayIntervalId);
3300                            autoplayIntervalId = undefined;
3301                        }
3302                    }
3303                }, autoInterval);
3304            }
3305        }, autoDelay);
3306    };
3307    _this.stopAutoplay = function (internal) {
3308        if (_this.support.transitions) {
3309            if (!autoplayTimeoutId) return;
3310            if (autoplayTimeoutId) clearTimeout(autoplayTimeoutId);
3311            autoplayTimeoutId = undefined;
3312            if (internal && !params.autoplayDisableOnInteraction) {
3313                _this.wrapperTransitionEnd(function () {
3314                    autoplay();
3315                });
3316            }
3317            _this.callPlugins('onAutoplayStop');
3318            if (params.onAutoplayStop) _this.fireCallback(params.onAutoplayStop, _this);
3319        }
3320        else {
3321            if (autoplayIntervalId) clearInterval(autoplayIntervalId);
3322            autoplayIntervalId = undefined;
3323            _this.callPlugins('onAutoplayStop');
3324            if (params.onAutoplayStop) _this.fireCallback(params.onAutoplayStop, _this);
3325        }
3326    };
3327    function autoplay() {
3328        autoplayTimeoutId = setTimeout(function () {
3329            if (params.loop) {
3330                _this.fixLoop();
3331                _this.swipeNext(true, true);
3332            }
3333            else if (!_this.swipeNext(true, true)) {
3334                if (!params.autoplayStopOnLast) _this.swipeTo(0);
3335                else {
3336                    clearTimeout(autoplayTimeoutId);
3337                    autoplayTimeoutId = undefined;
3338                }
3339            }
3340            _this.wrapperTransitionEnd(function () {
3341                if (typeof autoplayTimeoutId !== 'undefined') autoplay();
3342            });
3343            if ( _this.params.transition === "fade") {
3344                if (typeof autoplayTimeoutId !== 'undefined') autoplay();
3345            }
3346
3347        }, params.autoplay);
3348    }
3349    /*==================================================
3350        Loop
3351    ====================================================*/
3352    _this.loopCreated = false;
3353    _this.removeLoopedSlides = function () {
3354        if (_this.loopCreated) {
3355            for (var i = 0; i < _this.slides.length; i++) {
3356                if (_this.slides[i].getData('looped') === true) _this.wrapper.removeChild(_this.slides[i]);
3357            }
3358        }
3359    };
3360
3361    _this.createLoop = function () {
3362        if (_this.slides.length === 0) return;
3363        if (params.slidesPerView === 'auto') {
3364            _this.loopedSlides = params.loopedSlides || 1;
3365        }
3366        else {
3367            _this.loopedSlides = Math.floor(params.slidesPerView) + params.loopAdditionalSlides;
3368        }
3369
3370        if (_this.loopedSlides > _this.slides.length) {
3371            _this.loopedSlides = _this.slides.length;
3372        }
3373
3374        var slideFirstHTML = '',
3375            slideLastHTML = '',
3376            i;
3377        var slidesSetFullHTML = '';
3378        /**
3379                loopedSlides is too large if loopAdditionalSlides are set.
3380                Need to divide the slides by maximum number of slides existing.
3381
3382                @author        Tomaz Lovrec <[email protected]>
3383        */
3384        var numSlides = _this.slides.length;
3385        var fullSlideSets = Math.floor(_this.loopedSlides / numSlides);
3386        var remainderSlides = _this.loopedSlides % numSlides;
3387        // assemble full sets of slides
3388        for (i = 0; i < (fullSlideSets * numSlides); i++) {
3389            var j = i;
3390            if (i >= numSlides) {
3391                var over = Math.floor(i / numSlides);
3392                j = i - (numSlides * over);
3393            }
3394            slidesSetFullHTML += _this.slides[j].outerHTML;
3395        }
3396        // assemble remainder slides
3397        // assemble remainder appended to existing slides
3398        for (i = 0; i < remainderSlides;i++) {
3399            slideLastHTML += addClassToHtmlString(params.slideDuplicateClass, _this.slides[i].outerHTML);
3400        }
3401        // assemble slides that get preppended to existing slides
3402        for (i = numSlides - remainderSlides; i < numSlides;i++) {
3403            slideFirstHTML += addClassToHtmlString(params.slideDuplicateClass, _this.slides[i].outerHTML);
3404        }
3405        // assemble all slides
3406        var slides = slideFirstHTML + slidesSetFullHTML + wrapper.innerHTML + slidesSetFullHTML + slideLastHTML;
3407        // set the slides
3408        wrapper.innerHTML = slides;
3409
3410        _this.loopCreated = true;
3411        _this.calcSlides();
3412
3413        //Update Looped Slides with special class
3414        for (i = 0; i < _this.slides.length; i++) {
3415            if (i < _this.loopedSlides || i >= _this.slides.length - _this.loopedSlides) _this.slides[i].setData('looped', true);
3416        }
3417        _this.callPlugins('onCreateLoop');
3418
3419    };
3420
3421    _this.fixLoop = function () {
3422        var newIndex;
3423        //Fix For Negative Oversliding
3424        if (_this.activeIndex < _this.loopedSlides) {
3425            newIndex = _this.slides.length - _this.loopedSlides * 3 + _this.activeIndex;
3426            _this.swipeTo(newIndex, 0, false);
3427        }
3428        //Fix For Positive Oversliding
3429        else if ((params.slidesPerView === 'auto' && _this.activeIndex >= _this.loopedSlides * 2) || (_this.activeIndex > _this.slides.length - params.slidesPerView * 2)) {
3430            newIndex = -_this.slides.length + _this.activeIndex + _this.loopedSlides;
3431            _this.swipeTo(newIndex, 0, false);
3432        }
3433    };
3434
3435    /*==================================================
3436        Slides Loader
3437    ====================================================*/
3438    _this.loadSlides = function () {
3439        var slidesHTML = '';
3440        _this.activeLoaderIndex = 0;
3441        var slides = params.loader.slides;
3442        var slidesToLoad = params.loader.loadAllSlides ? slides.length : params.slidesPerView * (1 + params.loader.surroundGroups);
3443        for (var i = 0; i < slidesToLoad; i++) {
3444            if (params.loader.slidesHTMLType === 'outer') slidesHTML += slides[i];
3445            else {
3446                slidesHTML += '<' + params.slideElement + ' class="' + params.slideClass + '" data-swiperindex="' + i + '">' + slides[i] + '</' + params.slideElement + '>';
3447            }
3448        }
3449        _this.wrapper.innerHTML = slidesHTML;
3450        _this.calcSlides(true);
3451        //Add permanent transitionEnd callback
3452        if (!params.loader.loadAllSlides) {
3453            _this.wrapperTransitionEnd(_this.reloadSlides, true);
3454        }
3455    };
3456
3457    _this.reloadSlides = function () {
3458        var slides = params.loader.slides;
3459        var newActiveIndex = parseInt(_this.activeSlide().data('swiperindex'), 10);
3460        if (newActiveIndex < 0 || newActiveIndex > slides.length - 1) return; //<-- Exit
3461        _this.activeLoaderIndex = newActiveIndex;
3462        var firstIndex = Math.max(0, newActiveIndex - params.slidesPerView * params.loader.surroundGroups);
3463        var lastIndex = Math.min(newActiveIndex + params.slidesPerView * (1 + params.loader.surroundGroups) - 1, slides.length - 1);
3464        //Update Transforms
3465        if (newActiveIndex > 0) {
3466            var newTransform = -slideSize * (newActiveIndex - firstIndex);
3467            _this.setWrapperTranslate(newTransform);
3468            _this.setWrapperTransition(0);
3469        }
3470        var i; // loop index
3471        //New Slides
3472        if (params.loader.logic === 'reload') {
3473            _this.wrapper.innerHTML = '';
3474            var slidesHTML = '';
3475            for (i = firstIndex; i <= lastIndex; i++) {
3476                slidesHTML += params.loader.slidesHTMLType === 'outer' ? slides[i] : '<' + params.slideElement + ' class="' + params.slideClass + '" data-swiperindex="' + i + '">' + slides[i] + '</' + params.slideElement + '>';
3477            }
3478            _this.wrapper.innerHTML = slidesHTML;
3479        }
3480        else {
3481            var minExistIndex = 1000;
3482            var maxExistIndex = 0;
3483
3484            for (i = 0; i < _this.slides.length; i++) {
3485                var index = _this.slides[i].data('swiperindex');
3486                if (index < firstIndex || index > lastIndex) {
3487                    _this.wrapper.removeChild(_this.slides[i]);
3488                }
3489                else {
3490                    minExistIndex = Math.min(index, minExistIndex);
3491                    maxExistIndex = Math.max(index, maxExistIndex);
3492                }
3493            }
3494            for (i = firstIndex; i <= lastIndex; i++) {
3495                var newSlide;
3496                if (i < minExistIndex) {
3497                    newSlide = document.createElement(params.slideElement);
3498                    newSlide.className = params.slideClass;
3499                    newSlide.setAttribute('data-swiperindex', i);
3500                    newSlide.innerHTML = slides[i];
3501                    _this.wrapper.insertBefore(newSlide, _this.wrapper.firstChild);
3502                }
3503                if (i > maxExistIndex) {
3504                    newSlide = document.createElement(params.slideElement);
3505                    newSlide.className = params.slideClass;
3506                    newSlide.setAttribute('data-swiperindex', i);
3507                    newSlide.innerHTML = slides[i];
3508                    _this.wrapper.appendChild(newSlide);
3509                }
3510            }
3511        }
3512        //reInit
3513        _this.reInit(true);
3514    };
3515
3516    /*==================================================
3517        Make SwiftSwiper
3518    ====================================================*/
3519    function makeSwiftSwiper() {
3520        _this.calcSlides();
3521        if (params.loader.slides.length > 0 && _this.slides.length === 0) {
3522            _this.loadSlides();
3523        }
3524        if (params.loop) {
3525            _this.createLoop();
3526        }
3527        _this.init();
3528        initEvents();
3529        if (params.pagination) {
3530            _this.createPagination(true);
3531        }
3532
3533        if (params.loop || params.initialSlide > 0) {
3534            _this.swipeTo(params.initialSlide, 0, false);
3535        }
3536        else {
3537            _this.updateActiveSlide(0);
3538        }
3539        if (params.autoplay) {
3540            _this.startAutoplay();
3541        }
3542        /**
3543         * Set center slide index.
3544         *
3545         * @author        Tomaz Lovrec <[email protected]>
3546         */
3547        _this.centerIndex = _this.activeIndex;
3548
3549        // Callbacks
3550        if (params.onSwiftSwiperCreated) _this.fireCallback(params.onSwiftSwiperCreated, _this);
3551        _this.callPlugins('onSwiftSwiperCreated');
3552    }
3553
3554    makeSwiftSwiper();
3555};
3556
3557SwiftSwiper.prototype = {
3558    plugins : {},
3559
3560    /*==================================================
3561        Wrapper Operations
3562    ====================================================*/
3563    wrapperTransitionEnd : function (callback, permanent) {
3564        'use strict';
3565        var a = this,
3566            el = a.wrapper,
3567            events = ['webkitTransitionEnd', 'transitionend', 'oTransitionEnd', 'MSTransitionEnd', 'msTransitionEnd'],
3568            i;
3569
3570        function fireCallBack(e) {
3571            if (e.target !== el) return;
3572            callback(a);
3573            if (a.params.queueEndCallbacks) a._queueEndCallbacks = false;
3574            if (!permanent) {
3575                for (i = 0; i < events.length; i++) {
3576                    a.h.removeEventListener(el, events[i], fireCallBack);
3577                }
3578            }
3579        }
3580
3581        if (callback) {
3582            for (i = 0; i < events.length; i++) {
3583                a.h.addEventListener(el, events[i], fireCallBack);
3584            }
3585        }
3586    },
3587
3588    getWrapperTranslate : function (axis) {
3589        'use strict';
3590        var el = this.wrapper,
3591            matrix, curTransform, curStyle, transformMatrix;
3592
3593        // automatic axis detection
3594        if (typeof axis === 'undefined') {
3595            axis = this.params.mode === 'horizontal' ? 'x' : 'y';
3596        }
3597
3598        if (this.support.transforms && this.params.useCSS3Transforms) {
3599            curStyle = window.getComputedStyle(el, null);
3600            if (window.WebKitCSSMatrix) {
3601                // Some old versions of Webkit choke when 'none' is passed; pass
3602                // empty string instead in this case
3603                transformMatrix = new WebKitCSSMatrix(curStyle.webkitTransform === 'none' ? '' : curStyle.webkitTransform);
3604            }
3605            else {
3606                transformMatrix = curStyle.MozTransform || curStyle.OTransform || curStyle.MsTransform || curStyle.msTransform  || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
3607                matrix = transformMatrix.toString().split(',');
3608            }
3609
3610            if (axis === 'x') {
3611                //Latest Chrome and webkits Fix
3612                if (window.WebKitCSSMatrix)
3613                    curTransform = transformMatrix.m41;
3614                //Crazy IE10 Matrix
3615                else if (matrix.length === 16)
3616                    curTransform = parseFloat(matrix[12]);
3617                //Normal Browsers
3618                else
3619                    curTransform = parseFloat(matrix[4]);
3620            }
3621            if (axis === 'y') {
3622                //Latest Chrome and webkits Fix
3623                if (window.WebKitCSSMatrix)
3624                    curTransform = transformMatrix.m42;
3625                //Crazy IE10 Matrix
3626                else if (matrix.length === 16)
3627                    curTransform = parseFloat(matrix[13]);
3628                //Normal Browsers
3629                else
3630                    curTransform = parseFloat(matrix[5]);
3631            }
3632        }
3633        else {
3634            if (axis === 'x') curTransform = parseFloat(el.style.left, 10) || 0;
3635            if (axis === 'y') curTransform = parseFloat(el.style.top, 10) || 0;
3636        }
3637        return curTransform || 0;
3638    },
3639
3640    setWrapperTranslate : function (x, y, z) {
3641        'use strict';
3642        var es = this.wrapper.style,
3643            coords = {x: 0, y: 0, z: 0},
3644            translate;
3645
3646        // passed all coordinates
3647        if (arguments.length === 3) {
3648            coords.x = x;
3649            coords.y = y;
3650            coords.z = z;
3651        }
3652
3653        // passed one coordinate and optional axis
3654        else {
3655            if (typeof y === 'undefined') {
3656                y = this.params.mode === 'horizontal' ? 'x' : 'y';
3657            }
3658            coords[y] = x;
3659        }
3660
3661        if (this.support.transforms && this.params.useCSS3Transforms) {
3662            translate = this.support.transforms3d ? 'translate3d(' + coords.x + 'px, ' + coords.y + 'px, ' + coords.z + 'px)' : 'translate(' + coords.x + 'px, ' + coords.y + 'px)';
3663            es.webkitTransform = es.MsTransform = es.msTransform = es.MozTransform = es.OTransform = es.transform = translate;
3664        }
3665        else {
3666            es.left = coords.x + 'px';
3667            es.top  = coords.y + 'px';
3668        }
3669        this.callPlugins('onSetWrapperTransform', coords);
3670        if (this.params.onSetWrapperTransform) this.fireCallback(this.params.onSetWrapperTransform, this, coords);
3671    },
3672
3673    setWrapperTransition : function (duration) {
3674        'use strict';
3675        var es = this.wrapper.style;
3676        es.webkitTransitionDuration = es.MsTransitionDuration = es.msTransitionDuration = es.MozTransitionDuration = es.OTransitionDuration = es.transitionDuration = (duration / 1000) + 's';
3677        this.callPlugins('onSetWrapperTransition', {duration: duration});
3678        if (this.params.onSetWrapperTransition) this.fireCallback(this.params.onSetWrapperTransition, this, duration);
3679
3680    },
3681
3682    /*==================================================
3683        Helpers
3684    ====================================================*/
3685    h : {
3686        getWidth: function (el, outer, round) {
3687            'use strict';
3688            var width = window.getComputedStyle(el, null).getPropertyValue('width');
3689            var returnWidth = parseFloat(width);
3690            //IE Fixes
3691            if (isNaN(returnWidth) || width.indexOf('%') > 0 || returnWidth < 0) {
3692                returnWidth = el.offsetWidth - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-left')) - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-right'));
3693            }
3694            if (outer) returnWidth += parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-left')) + parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-right'));
3695            if (round) return Math.ceil(returnWidth);
3696            else return returnWidth;
3697        },
3698        getHeight: function (el, outer, round) {
3699            'use strict';
3700            if (outer) return el.offsetHeight;
3701
3702            var height = window.getComputedStyle(el, null).getPropertyValue('height');
3703            var returnHeight = parseFloat(height);
3704            //IE Fixes
3705            if (isNaN(returnHeight) || height.indexOf('%') > 0 || returnHeight < 0) {
3706                returnHeight = el.offsetHeight - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-top')) - parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-bottom'));
3707            }
3708            if (outer) returnHeight += parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-top')) + parseFloat(window.getComputedStyle(el, null).getPropertyValue('padding-bottom'));
3709            if (round) return Math.ceil(returnHeight);
3710            else return returnHeight;
3711        },
3712        getOffset: function (el) {
3713            'use strict';
3714            var box = el.getBoundingClientRect();
3715            var body = document.body;
3716            var clientTop  = el.clientTop  || body.clientTop  || 0;
3717            var clientLeft = el.clientLeft || body.clientLeft || 0;
3718            var scrollTop  = window.pageYOffset || el.scrollTop;
3719            var scrollLeft = window.pageXOffset || el.scrollLeft;
3720            if (document.documentElement && !window.pageYOffset) {
3721                //IE7-8
3722                scrollTop  = document.documentElement.scrollTop;
3723                scrollLeft = document.documentElement.scrollLeft;
3724            }
3725            return {
3726                top: box.top  + scrollTop  - clientTop,
3727                left: box.left + scrollLeft - clientLeft
3728            };
3729        },
3730        windowWidth : function () {
3731            'use strict';
3732            if (window.innerWidth) return window.innerWidth;
3733            else if (document.documentElement && document.documentElement.clientWidth) return document.documentElement.clientWidth;
3734        },
3735        windowHeight : function () {
3736            'use strict';
3737            if (window.innerHeight) return window.innerHeight;
3738            else if (document.documentElement && document.documentElement.clientHeight) return document.documentElement.clientHeight;
3739        },
3740        windowScroll : function () {
3741            'use strict';
3742            if (typeof pageYOffset !== 'undefined') {
3743                return {
3744                    left: window.pageXOffset,
3745                    top: window.pageYOffset
3746                };
3747            }
3748            else if (document.documentElement) {
3749                return {
3750                    left: document.documentElement.scrollLeft,
3751                    top: document.documentElement.scrollTop
3752                };
3753            }
3754        },
3755
3756        addEventListener : function (el, event, listener, useCapture) {
3757            'use strict';
3758            if (typeof useCapture === 'undefined') {
3759                useCapture = false;
3760            }
3761
3762            if (el.addEventListener) {
3763                el.addEventListener(event, listener, useCapture);
3764            }
3765            else if (el.attachEvent) {
3766                el.attachEvent('on' + event, listener);
3767            }
3768        },
3769
3770        removeEventListener : function (el, event, listener, useCapture) {
3771            'use strict';
3772            if (typeof useCapture === 'undefined') {
3773                useCapture = false;
3774            }
3775
3776            if (el.removeEventListener) {
3777                el.removeEventListener(event, listener, useCapture);
3778            }
3779            else if (el.detachEvent) {
3780                el.detachEvent('on' + event, listener);
3781            }
3782        }
3783    },
3784    setTransform : function (el, transform) {
3785        'use strict';
3786        var es = el.style;
3787        es.webkitTransform = es.MsTransform = es.msTransform = es.MozTransform = es.OTransform = es.transform = transform;
3788    },
3789    setTranslate : function (el, translate) {
3790        'use strict';
3791        var es = el.style;
3792        var pos = {
3793            x : translate.x || 0,
3794            y : translate.y || 0,
3795            z : translate.z || 0
3796        };
3797        var transformString = this.support.transforms3d ? 'translate3d(' + (pos.x) + 'px,' + (pos.y) + 'px,' + (pos.z) + 'px)' : 'translate(' + (pos.x) + 'px,' + (pos.y) + 'px)';
3798        es.webkitTransform = es.MsTransform = es.msTransform = es.MozTransform = es.OTransform = es.transform = transformString;
3799        if (!this.support.transforms) {
3800            es.left = pos.x + 'px';
3801            es.top = pos.y + 'px';
3802        }
3803    },
3804    setTransition : function (el, duration) {
3805        'use strict';
3806        var es = el.style;
3807        es.webkitTransitionDuration = es.MsTransitionDuration = es.msTransitionDuration = es.MozTransitionDuration = es.OTransitionDuration = es.transitionDuration = duration + 'ms';
3808    },
3809    /*==================================================
3810        Feature Detection
3811    ====================================================*/
3812    support: {
3813
3814        touch : (window.Modernizr && Modernizr.touch === true) || (function () {
3815            'use strict';
3816            return !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch);
3817        })(),
3818
3819        transforms3d : (window.Modernizr && Modernizr.csstransforms3d === true) || (function () {
3820            'use strict';
3821            var div = document.createElement('div').style;
3822            return ('webkitPerspective' in div || 'MozPerspective' in div || 'OPerspective' in div || 'MsPerspective' in div || 'perspective' in div);
3823        })(),
3824
3825        transforms : (window.Modernizr && Modernizr.csstransforms === true) || (function () {
3826            'use strict';
3827            var div = document.createElement('div').style;
3828            return ('transform' in div || 'WebkitTransform' in div || 'MozTransform' in div || 'msTransform' in div || 'MsTransform' in div || 'OTransform' in div);
3829        })(),
3830
3831        transitions : (window.Modernizr && Modernizr.csstransitions === true) || (function () {
3832            'use strict';
3833            var div = document.createElement('div').style;
3834            return ('transition' in div || 'WebkitTransition' in div || 'MozTransition' in div || 'msTransition' in div || 'MsTransition' in div || 'OTransition' in div);
3835        })(),
3836
3837        classList : (function () {
3838            'use strict';
3839            var div = document.createElement('div');
3840            return 'classList' in div;
3841        })()
3842    },
3843
3844    browser : {
3845
3846        ie8 : (function () {
3847            'use strict';
3848            var rv = -1; // Return value assumes failure.
3849            if (navigator.appName === 'Microsoft Internet Explorer') {
3850                var ua = navigator.userAgent;
3851                var re = new RegExp(/MSIE ([0-9]{1,}[\.0-9]{0,})/);
3852                if (re.exec(ua) !== null)
3853                    rv = parseFloat(RegExp.$1);
3854            }
3855            return rv !== -1 && rv < 9;
3856        })(),
3857
3858        ie10 : window.navigator.msPointerEnabled,
3859        ie11 : window.navigator.pointerEnabled
3860    }
3861};
3862
3863/*=========================
3864  jQuery & Zepto Plugins
3865  ===========================*/
3866if (window.jQuery || window.Zepto) {
3867    (function ($) {
3868        'use strict';
3869        $.fn.swiper = function (params) {
3870            var firstInstance;
3871            this.each(function (i) {
3872                var that = $(this);
3873                var s = new SwiftSwiper(that[0], params);
3874                if (!i) firstInstance = s;
3875                that.data('swiper', s);
3876            });
3877            return firstInstance;
3878        };
3879    })(window.jQuery || window.Zepto);
3880}
3881
3882// CommonJS support
3883if (typeof(module) !== 'undefined') {
3884    module.exports = SwiftSwiper;
3885
3886// requirejs support
3887} else if (typeof define === 'function' && define.amd) {
3888    define([], function () {
3889        'use strict';
3890        return SwiftSwiper;
3891    });
3892}
3893
3894/*
3895 * SwiftSwiper Smooth Progress 1.1.0
3896 * Smooth progress plugin for SwiftSwiper
3897 *
3898 * http://www.idangero.us/sliders/swiper/plugins/progress.php
3899 *
3900 * Copyright 2010-2014, Vladimir Kharlampidi
3901 * The iDangero.us
3902 * http://www.idangero.us/
3903 *
3904 * Licensed under GPL & MIT
3905 *
3906 * Released on: January 29, 2014
3907 */
3908SwiftSwiper.prototype.plugins.progress = function( a ) {
3909    function b() {
3910        for ( var b = 0; b < a.slides.length; b++ ) {
3911            var c = a.slides[b];
3912            c.progressSlideSize = e ? a.h.getWidth( c ) : a.h.getHeight( c ), c.progressSlideOffset = "offsetLeft"in c ? e ? c.offsetLeft : c.offsetTop : e ? c.getOffset().left - a.h.getOffset( a.container ).left : c.getOffset().top - a.h.getOffset( a.container ).top
3913        }
3914        d = e ? a.h.getWidth( a.wrapper ) + a.wrapperLeft + a.wrapperRight - a.width : a.h.getHeight( a.wrapper ) + a.wrapperTop + a.wrapperBottom - a.height
3915    }
3916
3917    function c( b ) {
3918        var c, b = b || {x: 0, y: 0, z: 0};
3919        c = 1 == a.params.centeredSlides ? e ? -b.x + a.width / 2 : -b.y + a.height / 2 : e ? -b.x : -b.y;
3920        for ( var f = 0; f < a.slides.length; f++ ) {
3921            var g = a.slides[f], h = 1 == a.params.centeredSlides ? g.progressSlideSize / 2 : 0, i = (c - g.progressSlideOffset - h) / g.progressSlideSize;
3922            g.progress = i
3923        }
3924        a.progress = e ? -b.x / d : -b.y / d, a.params.onProgressChange && a.fireCallback(
3925            a.params.onProgressChange, a
3926        )
3927    }
3928
3929    var d, e = "horizontal" == a.params.mode, f = {
3930        onFirstInit: function() {
3931            b(), c( {x: a.getWrapperTranslate( "x" ), y: a.getWrapperTranslate( "y" )} )
3932        }, onInit: function() {
3933            b()
3934        }, onSetWrapperTransform: function( a ) {
3935            c( a )
3936        }
3937    };
3938    return f;
3939};
3940
3941/////////////////////////////////////////////
3942// THROTTLED RESIZE
3943/////////////////////////////////////////////
3944(function(d){var c=d.event,a,e={_:0},f=0,g,b;a=c.special.throttledresize={setup:function(){d(this).on("resize",a.handler)},teardown:function(){d(this).off("resize",a.handler)},handler:function(k,h){var j=this,i=arguments;g=true;if(!b){setInterval(function(){f++;if(f>a.threshold&&g||h){k.type="throttledresize";c.dispatch.apply(j,i);g=false;f=0}if(f>9){d(e).stop();b=false;f=0}},30);b=true}},threshold:0}})(jQuery);
3945
3946
3947/////////////////////////////////////////////
3948// CANVIDEOAUTOPLAY
3949/////////////////////////////////////////////
3950(function ($) {
3951   $.extend({
3952      'canVideoautoplay' : function ( callback ) {
3953         
3954         var testStarted = false;
3955         try {
3956         
3957            var playsinline = navigator.userAgent.match(/(iPhone|iPod)/g) ? ('playsInline' in document.createElement('video')) : true;
3958            if (!playsinline) {
3959               return callback(false);
3960            }
3961            
3962            var src = 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAA7RtZGF0AAACrAYF//+o3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE1MiByMTkgYmEyNDg5OSAtIEguMjY0L01QRUctNCBBVkMgY29kZWMgLSBDb3B5bGVmdCAyMDAzLTIwMTcgLSBodHRwOi8vd3d3LnZpZGVvbGFuLm9yZy94MjY0Lmh0bWwgLSBvcHRpb25zOiBjYWJhYz0xIHJlZj0zIGRlYmxvY2s9MTowOjAgYW5hbHlzZT0weDM6MHgxMTMgbWU9aGV4IHN1Ym1lPTcgcHN5PTEgcHN5X3JkPTEuMDA6MC4wMCBtaXhlZF9yZWY9MSBtZV9yYW5nZT0xNiBjaHJvbWFfbWU9MSB0cmVsbGlzPTEgOHg4ZGN0PTEgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0xIGNocm9tYV9xcF9vZmZzZXQ9LTIgdGhyZWFkcz0zIGxvb2thaGVhZF90aHJlYWRzPTEgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MyBiX3B5cmFtaWQ9MiBiX2FkYXB0PTEgYl9iaWFzPTAgZGlyZWN0PTEgd2VpZ2h0Yj0xIG9wZW5fZ29wPTAgd2VpZ2h0cD0yIGtleWludD0yNTAga2V5aW50X21pbj0yNSBzY2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmNfbG9va2FoZWFkPTQwIHJjPWNyZiBtYnRyZWU9MSBjcmY9MjguMCBxY29tcD0wLjYwIHFwbWluPTAgcXBtYXg9NjkgcXBzdGVwPTQgaXBfcmF0aW89MS40MCBhcT0xOjEuMDAAgAAAACpliIQAJ//+8dzwKZrlxoFv6nFTjrH/8I5IvpuR7wM+8DluLAAQcGNdwkEAAAAKQZokbEJ/8yAHLAAAAAhBnkJ4jf8JeQAAAAgBnmF0Rf8KSAAAAAgBnmNqRf8KSQAAABBBmmhJqEFomUwIR//kQBXxAAAACUGehkURLG8JeQAAAAgBnqV0Rf8KSQAAAAgBnqdqRf8KSAAAAA9BmqxJqEFsmUwI/4cAU8AAAAAJQZ7KRRUsbwl5AAAACAGe6XRF/wpIAAAACAGe62pF/wpIAAAADkGa70moQWyZTAi/AAJPAAAACUGfDUUVLG8JeQAAAAgBny5qRf8KS
3962QAAA8ptb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAACFwABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAC9HRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAACFwAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAoAAAAFoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAhcAAAMAAAEAAAAAAmxtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAACzgAAAYAFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAIXbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAB13N0YmwAAACXc3RzZAAAAAAAAAABAAAAh2F2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAoABaAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwFkAAv/4QAYZ2QAC6zZQo35IQAAAwAMAAADAs4PFCmWAQAGaOviSyLAAAAAGHN0dHMAAAAAAAAAAQAAABAAAAGAAAAAFHN0c3MAAAAAAAAAAQAAAAEAAACIY3R0cwAAAAAAAAAPAAAAAQAAAwAAAAABAAAHgAAAAAEAAAMAAAAAAQAAAAAAAAABAAABgAAAAAEAAAeAAAAAAQAAAwAAAAABAAAAAAAAAAEAAAGAAAAAAQAAB4AAAAABAAADAAAAAAEAAAAAAAAAAQAAAYAAAAABAAAGAAAAAAIAAAGAAAAAHHN0c2MAAAAAAAAAAQAAAAEAAAAQAAAAAQAAAFRzdHN6AAAAAAAAAAAAAAAQAAAC3gAAAA4AAAAMAAAADAAAAAwAAAAUAAAADQAAAAwAAAAMAAAAEwAAAA0AAAAMAAAADAAAABIAAAANAAAADAAAABRzdGNvAAAAAAAAAAEAAAAwAAAAYnVkdGEAAABabWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcmFwcGwAAAAAAAAAAAAAAAAtaWxzdAAAACWpdG9vAAAAHWRhdGEAAAABAAAAAExhdmY1Ny43Ny4xMDA=';
3963            var $video = $('<video src="'+src+'" controls playsinline muted width="20" height="20" style="position:fixed;z-index:1000;top:0;left:0"></video>');
3964            $('body').prepend($video);
3965            
3966            testStarted = true;
3967            $video[0].play();
3968         
3969            $video[0].onplay = function() {
3970               this.playing = true;
3971            };
3972
3973            $video[0].oncanplay = function() {
3974               if ($video[0].playing) {
3975                  callback(true);
3976               } else {
3977                  callback(false);
3978               }
3979               $video[0].pause();
3980               $video.remove();
3981            };
3982         } catch(e) {}
3983         
3984         if (!testStarted) {
3985            callback(false);
3986         }
3987      }
3988   });
3989})(jQuery);

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.