PageSourceSearch

https://northgardenshs.com/apps-shared/js/bxslider/jquery.bxslider.js

js northgardenshs.com collected 2026-09-30 21:59:27 UTC 81,018 bytes, 1,822 lines download raw bytes

vendor: 77,338 bytes, lines 1-1724
1/**
2 * bxSlider v4.2.1d
3 * Copyright 2013-2017 Steven Wanderski
4 * Written while drinking Belgian ales and listening to jazz
5 * Licensed under MIT (http://opensource.org/licenses/MIT)
6 */
7
8;(function ($) {
9
10    var defaults = {
11
12        // GENERAL
13        mode: 'horizontal',
14        slideSelector: '',
15        infiniteLoop: true,
16        hideControlOnEnd: false,
17        speed: 500,
18        easing: null,
19        slideMargin: 0,
20        startSlide: 0,
21        randomStart: false,
22        captions: false,
23        ticker: false,
24        tickerHover: false,
25        adaptiveHeight: false,
26        adaptiveHeightSpeed: 500,
27        video: false,
28        useCSS: true,
29        preloadImages: 'visible',
30        responsive: true,
31        slideZIndex: 50,
32        wrapperClass: 'bx-wrapper',
33
34        // TOUCH
35        touchEnabled: true,
36        swipeThreshold: 50,
37        oneToOneTouch: true,
38        preventDefaultSwipeX: true,
39        preventDefaultSwipeY: false,
40
41        // ACCESSIBILITY
42        ariaLive: true,
43        ariaHidden: true,
44
45        // KEYBOARD
46        keyboardEnabled: false,
47
48        // PAGER
49        pager: true,
50        pagerType: 'full',
51        pagerShortSeparator: ' / ',
52        pagerSelector: null,
53        buildPager: null,
54        pagerCustom: null,
55
56        // CONTROLS
57        controls: true,
58        nextText: 'Next',
59        prevText: 'Prev',
60        nextSelector: null,
61        prevSelector: null,
62        autoControls: false,
63        startText: 'Start',
64        stopText: 'Stop',
65        autoControlsCombine: false,
66        autoControlsSelector: null,
67
68        // AUTO
69        auto: false,
70        pause: 4000,
71        autoStart: true,
72        autoDirection: 'next',
73        stopAutoOnClick: false,
74        autoHover: false,
75        autoDelay: 0,
76        autoSlideForOnePage: false,
77
78        // CAROUSEL
79        minSlides: 1,
80        maxSlides: 1,
81        moveSlides: 0,
82        slideWidth: 0,
83        shrinkItems: false,
84
85        // CALLBACKS
86        onSliderLoad: function () {
87            return true;
88        },
89        onSlideBefore: function () {
90            return true;
91        },
92        onSlideAfter: function () {
93            return true;
94        },
95        onSlideNext: function () {
96            return true;
97        },
98        onSlidePrev: function () {
99            return true;
100        },
101        onSliderResize: function () {
102            return true;
103        },
104        onAutoChange: function () {
105            return true;
106        } //calls when auto slides starts and stops
107    };
108
109    $.fn.bxSlider = function (options) {
110
111        if (this.length === 0) {
112            return this;
113        }
114
115        // support multiple elements
116        if (this.length > 1) {
117            this.each(function () {
118                $(this).bxSlider(options);
119            });
120            return this;
121        }
122
123        // create a namespace to be used throughout the plugin
124        var slider = {},
125            // set a reference to our slider element
126            el = this,
127            // get the original window dimens (thanks a lot IE)
128            windowWidth = $(window).width(),
129            windowHeight = $(window).height();
130
131        // Return if slider is already initialized
132        if ($(el).data('bxSlider')) {
133            return;
134        }
135
136        /**
137         * ===================================================================================
138         * = PRIVATE FUNCTIONS
139         * ===================================================================================
140         */
141
142        /**
143         * Initializes namespace settings to be used throughout plugin
144         */
145        var init = function () {
146            // Return if slider is already initialized
147            if ($(el).data('bxSlider')) {
148                return;
149            }
150            // merge user-supplied options with the defaults
151            slider.settings = $.extend({}, defaults, options);
152            // parse slideWidth setting
153            slider.settings.slideWidth = parseInt(slider.settings.slideWidth);
154            // store the original children
155            slider.children = el.children(slider.settings.slideSelector);
156            // check if actual number of slides is less than minSlides / maxSlides
157            if (slider.children.length < slider.settings.minSlides) {
158                slider.settings.minSlides = slider.children.length;
159            }
160            if (slider.children.length < slider.settings.maxSlides) {
161                slider.settings.maxSlides = slider.children.length;
162            }
163            // if random start, set the startSlide setting to random number
164            if (slider.settings.randomStart) {
165                slider.settings.startSlide = Math.floor(Math.random() * slider.children.length);
166            }
167            // store active slide information
168            slider.active = {index: slider.settings.startSlide};
169            // store if the slider is in carousel mode (displaying / moving multiple slides)
170            slider.carousel = slider.settings.minSlides > 1 || slider.settings.maxSlides > 1;
171            // if carousel, force preloadImages = 'all'
172            if (slider.carousel) {
173                slider.settings.preloadImages = 'all';
174            }
175            // calculate the min / max width thresholds based on min / max number of slides
176            // used to setup and update carousel slides dimensions
177            slider.minThreshold = (slider.settings.minSlides * slider.settings.slideWidth) + ((slider.settings.minSlides - 1) * slider.settings.slideMargin);
178            slider.maxThreshold = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin);
179            // store the current state of the slider (if currently animating, working is true)
180            slider.working = false;
181            // initialize the controls object
182            slider.controls = {};
183            // initialize an auto interval
184            slider.interval = null;
185            // determine which property to use for transitions
186            slider.animProp = slider.settings.mode === 'vertical' ? 'top' : 'left';
187            // determine if hardware acceleration can be used
188            slider.usingCSS = slider.settings.useCSS && slider.settings.mode !== 'fade' && (function () {
189                // create our test div element
190                var div = document.createElement('div'),
191                    // css transition properties
192                    props = ['WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective'];
193                // test for each property
194                for (var i = 0; i < props.length; i++) {
195                    if (div.style[props[i]] !== undefined) {
196                        slider.cssPrefix = props[i].replace('Perspective', '').toLowerCase();
197                        slider.animProp = '-' + slider.cssPrefix + '-transform';
198                        return true;
199                    }
200                }
201                return false;
202            }());
203            // if vertical mode always make maxSlides and minSlides equal
204            if (slider.settings.mode === 'vertical') {
205                slider.settings.maxSlides = slider.settings.minSlides;
206            }
207            // save original style data
208            el.data('origStyle', el.attr('style'));
209            el.children(slider.settings.slideSelector).each(function () {
210                $(this).data('origStyle', $(this).attr('style'));
211            });
212
213            // perform all DOM / CSS modifications
214            setup();
215        };
216
217        /**
218         * Performs all DOM and CSS modifications
219         */
220        var setup = function () {
221            var preloadSelector = slider.children.eq(slider.settings.startSlide); // set the default preload selector (visible)
222
223            // wrap el in a wrapper
224            el.wrap('<div class="' + slider.settings.wrapperClass + '"><div class="bx-viewport"></div></div>');
225            // store a namespace reference to .bx-viewport
226            slider.viewport = el.parent();
227
228            // add aria-live if the setting is enabled and ticker mode is disabled
229            if (slider.settings.ariaLive && !slider.settings.ticker) {
230                slider.viewport.attr('aria-live', 'polite');
231            }
232            // add a loading div to display while images are loading
233            slider.loader = $('<div class="bx-loading" />');
234            slider.viewport.prepend(slider.loader);
235            // set el to a massive width, to hold any needed slides
236            // also strip any margin and padding from el
237            el.css({
238                width: slider.settings.mode === 'horizontal' ? (slider.children.length * 1000 + 215) + '%' : 'auto',
239                position: 'relative'
240            });
241            // if using CSS, add the easing property
242            if (slider.usingCSS && slider.settings.easing) {
243                el.css('-' + slider.cssPrefix + '-transition-timing-function', slider.settings.easing);
244                // if not using CSS and no easing value was supplied, use the default JS animation easing (swing)
245            } else if (!slider.settings.easing) {
246                slider.settings.easing = 'swing';
247            }
248            // make modifications to the viewport (.bx-viewport)
249            slider.viewport.css({
250                width: '100%',
251                overflow: 'hidden',
252                position: 'relative'
253            });
254            slider.viewport.parent().css({
255                maxWidth: getViewportMaxWidth()
256            });
257            // apply css to all slider children
258            slider.children.css({
259                // the float attribute is a reserved word in compressors like YUI compressor and need to be quoted #48
260                'float': slider.settings.mode === 'horizontal' ? 'left' : 'none',
261                listStyle: 'none',
262                position: 'relative'
263            });
264            // apply the calculated width after the float is applied to prevent scrollbar interference
265            slider.children.css('width', getSlideWidth());
266            // if slideMargin is supplied, add the css
267            if (slider.settings.mode === 'horizontal' && slider.settings.slideMargin > 0) {
268                slider.children.css('marginRight', slider.settings.slideMargin);
269            }
270            if (slider.settings.mode === 'vertical' && slider.settings.slideMargin > 0) {
271                slider.children.css('marginBottom', slider.settings.slideMargin);
272            }
273            // if "fade" mode, add positioning and z-index CSS
274            if (slider.settings.mode === 'fade') {
275                slider.children.css({
276                    position: 'absolute',
277                    zIndex: 0,
278                    display: 'none'
279                });
280                // prepare the z-index on the showing element
281                slider.children.eq(slider.settings.startSlide).css({
282                    zIndex: slider.settings.slideZIndex,
283                    display: 'block'
284                });
285            }
286            // create an element to contain all slider controls (pager, start / stop, etc)
287            slider.controls.el = $('<div class="bx-controls" />');
288            // if captions are requested, add them
289            if (slider.settings.captions) {
290                appendCaptions();
291            }
292            // check if startSlide is last slide
293            slider.active.last = slider.settings.startSlide === getPagerQty() - 1;
294            // if video is true, set up the fitVids plugin
295            if (slider.settings.video) {
296                el.fitVids();
297            }
298            //preloadImages
299            if (slider.settings.preloadImages === 'none') {
300                preloadSelector = null;
301            } else if (slider.settings.preloadImages === 'all' || slider.settings.ticker) {
302                preloadSelector = slider.children;
303            }
304            // only check for control addition if not in "ticker" mode
305            if (!slider.settings.ticker) {
306                // if controls are requested, add them
307                if (slider.settings.controls) {
308                    appendControls();
309                }
310                // if auto is true, and auto controls are requested, add them
311                if (slider.settings.auto && slider.settings.autoControls) {
312                    appendControlsAuto();
313                }
314                // if pager is requested, add it
315                if (slider.settings.pager) {
316                    appendPager();
317                }
318                // if any control option is requested, add the controls wrapper
319                if (slider.settings.controls || slider.settings.autoControls || slider.settings.pager) {
320                    slider.viewport.after(slider.controls.el);
321                }
322                // if ticker mode, do not allow a pager
323            } else {
324                slider.settings.pager = false;
325            }
326            if (preloadSelector === null) {
327                start();
328            } else {
329                loadElements(preloadSelector, start);
330            }
331        };
332
333        var loadElements = function (selector, callback) {
334            var total = selector.find('img:not([src=""]), iframe').length,
335                count = 0;
336            if (total === 0) {
337                callback();
338                return;
339            }
340            selector.find('img:not([src=""]), iframe').each(function () {
341                $(this).one('load error', function () {
342                    if (++count === total) {
343                        callback();
344                    }
345                }).each(function () {
346                    if (this.complete || this.src == '') {
347                        $(this).trigger('load');
348                    }
349                });
350            });
351        };
352
353        /**
354         * Start the slider
355         */
356        var start = function () {
357            // if infinite loop, prepare additional slides
358            if (slider.settings.infiniteLoop && slider.settings.mode !== 'fade' && !slider.settings.ticker) {
359                var slice = slider.settings.mode === 'vertical' ? slider.settings.minSlides : slider.settings.maxSlides,
360                    sliceAppend = slider.children.slice(0, slice).clone(true).addClass('bx-clone'),
361                    slicePrepend = slider.children.slice(-slice).clone(true).addClass('bx-clone');
362                if (slider.settings.ariaHidden) {
363                    sliceAppend.attr('aria-hidden', true);
364                    slicePrepend.attr('aria-hidden', true);
365                }
366                el.append(sliceAppend).prepend(slicePrepend);
367            }
368            // remove the loading DOM element
369            slider.loader.remove();
370            // set the left / top position of "el"
371            setSlidePosition();
372            // if "vertical" mode, always use adaptiveHeight to prevent odd behavior
373            if (slider.settings.mode === 'vertical') {
374                slider.settings.adaptiveHeight = true;
375            }
376            // set the viewport height
377            slider.viewport.height(getViewportHeight());
378            // make sure everything is positioned just right (same as a window resize)
379            el.redrawSlider();
380            // onSliderLoad callback
381            slider.settings.onSliderLoad.call(el, slider.active.index);
382            // slider has been fully initialized
383            slider.initialized = true;
384            // add the resize call to the window
385            if (slider.settings.responsive) {
386                $(window).on('resize', resizeWindow);
387            }
388            // if auto is true and has more than 1 page, start the show
389            if (slider.settings.auto && slider.settings.autoStart && (getPagerQty() > 1 || slider.settings.autoSlideForOnePage)) {
390                initAuto();
391            }
392            // if ticker is true, start the ticker
393            if (slider.settings.ticker) {
394                initTicker();
395            }
396            // if pager is requested, make the appropriate pager link active
397            if (slider.settings.pager) {
398                updatePagerActive(slider.settings.startSlide);
399            }
400            // check for any updates to the controls (like hideControlOnEnd updates)
401            if (slider.settings.controls) {
402                updateDirectionControls();
403            }
404            // if touchEnabled is true, setup the touch events
405            if (slider.settings.touchEnabled && !slider.settings.ticker) {
406                initTouch();
407            }
408            // if keyboardEnabled is true, setup the keyboard events
409            if (slider.settings.keyboardEnabled && !slider.settings.ticker) {
410                $(document).keydown(keyPress);
411            }
412        };
413
414        /**
415         * Returns the calculated height of the viewport, used to determine either adaptiveHeight or the maxHeight value
416         */
417        var getViewportHeight = function () {
418            var height = 0;
419            // first determine which children (slides) should be used in our height calculation
420            var children = $();
421            // if mode is not "vertical" and adaptiveHeight is false, include all children
422            if (slider.settings.mode !== 'vertical' && !slider.settings.adaptiveHeight) {
423                children = slider.children;
424            } else {
425                // if not carousel, return the single active child
426                if (!slider.carousel) {
427                    children = slider.children.eq(slider.active.index);
428                    // if carousel, return a slice of children
429                } else {
430                    // get the individual slide index
431                    var currentIndex = slider.settings.moveSlides === 1 ? slider.active.index : slider.active.index * getMoveBy();
432                    // add the current slide to the children
433                    children = slider.children.eq(currentIndex);
434                    // cycle through the remaining "showing" slides
435                    for (i = 1; i <= slider.settings.maxSlides - 1; i++) {
436                        // if looped back to the start
437                        if (currentIndex + i >= slider.children.length) {
438                            children = children.add(slider.children.eq(i - 1));
439                        } else {
440                            children = children.add(slider.children.eq(currentIndex + i));
441                        }
442                    }
443                }
444            }
445            // if "vertical" mode, calculate the sum of the heights of the children
446            if (slider.settings.mode === 'vertical') {
447                children.each(function (index) {
448                    height += $(this).outerHeight();
449                });
450                // add user-supplied margins
451                if (slider.settings.slideMargin > 0) {
452                    height += slider.settings.slideMargin * (slider.settings.minSlides - 1);
453                }
454                // if not "vertical" mode, calculate the max height of the children
455            } else {
456                height = Math.max.apply(Math, children.map(function () {
457                    return $(this).outerHeight(false);
458                }).get());
459            }
460
461            if (slider.viewport.css('box-sizing') === 'border-box') {
462                height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom')) +
463                    parseFloat(slider.viewport.css('border-top-width')) + parseFloat(slider.viewport.css('border-bottom-width'));
464            } else if (slider.viewport.css('box-sizing') === 'padding-box') {
465                height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom'));
466            }
467
468            return height;
469        };
470
471        /**
472         * Returns the calculated width to be used for the outer wrapper / viewport
473         */
474        var getViewportMaxWidth = function () {
475            var width = '100%';
476            if (slider.settings.slideWidth > 0) {
477                if (slider.settings.mode === 'horizontal') {
478                    width = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin);
479                } else {
480                    width = slider.settings.slideWidth;
481                }
482            }
483            return width;
484        };
485
486        /**
487         * Returns the calculated width to be applied to each slide
488         */
489        var getSlideWidth = function () {
490            var newElWidth = slider.settings.slideWidth, // start with any user-supplied slide width
491                wrapWidth = slider.viewport.width();    // get the current viewport width
492            // if slide width was not supplied, or is larger than the viewport use the viewport width
493            if (slider.settings.slideWidth === 0 ||
494                (slider.settings.slideWidth > wrapWidth && !slider.carousel) ||
495                slider.settings.mode === 'vertical') {
496                newElWidth = wrapWidth;
497                // if carousel, use the thresholds to determine the width
498            } else if (slider.settings.maxSlides > 1 && slider.settings.mode === 'horizontal') {
499                if (wrapWidth > slider.maxThreshold) {
500                    return newElWidth;
501                } else if (wrapWidth < slider.minThreshold) {
502                    newElWidth = (wrapWidth - (slider.settings.slideMargin * (slider.settings.minSlides - 1))) / slider.settings.minSlides;
503                } else if (slider.settings.shrinkItems) {
504                    newElWidth = Math.floor((wrapWidth + slider.settings.slideMargin) / (Math.ceil((wrapWidth + slider.settings.slideMargin) / (newElWidth + slider.settings.slideMargin))) - slider.settings.slideMargin);
505                }
506            }
507            return newElWidth;
508        };
509
510        /**
511         * Returns the number of slides currently visible in the viewport (includes partially visible slides)
512         */
513        var getNumberSlidesShowing = function () {
514            var slidesShowing = 1,
515                childWidth = null;
516            if (slider.settings.mode === 'horizontal' && slider.settings.slideWidth > 0) {
517                // if viewport is smaller than minThreshold, return minSlides
518                if (slider.viewport.width() < slider.minThreshold) {
519                    slidesShowing = slider.settings.minSlides;
520                    // if viewport is larger than maxThreshold, return maxSlides
521                } else if (slider.viewport.width() > slider.maxThreshold) {
522                    slidesShowing = slider.settings.maxSlides;
523                    // if viewport is between min / max thresholds, divide viewport width by first child width
524                } else {
525                    childWidth = slider.children.first().width() + slider.settings.slideMargin;
526                    slidesShowing = Math.floor((slider.viewport.width() +
527                        slider.settings.slideMargin) / childWidth) || 1;
528                }
529                // if "vertical" mode, slides showing will always be minSlides
530            } else if (slider.settings.mode === 'vertical') {
531                slidesShowing = slider.settings.minSlides;
532            }
533            return slidesShowing;
534        };
535
536        /**
537         * Returns the number of pages (one full viewport of slides is one "page")
538         */
539        var getPagerQty = function () {
540            var pagerQty = 0,
541                breakPoint = 0,
542                counter = 0;
543            // if moveSlides is specified by the user
544            if (slider.settings.moveSlides > 0) {
545                if (slider.settings.infiniteLoop) {
546                    pagerQty = Math.ceil(slider.children.length / getMoveBy());
547                } else {
548                    // when breakpoint goes above children length, counter is the number of pages
549                    while (breakPoint < slider.children.length) {
550                        ++pagerQty;
551                        breakPoint = counter + getNumberSlidesShowing();
552                        counter += slider.settings.moveSlides <= getNumberSlidesShowing() ? slider.settings.moveSlides : getNumberSlidesShowing();
553                    }
554                    return counter;
555                }
556                // if moveSlides is 0 (auto) divide children length by sides showing, then round up
557            } else {
558                pagerQty = Math.ceil(slider.children.length / getNumberSlidesShowing());
559            }
560            return pagerQty;
561        };
562
563        /**
564         * Returns the number of individual slides by which to shift the slider
565         */
566        var getMoveBy = function () {
567            // if moveSlides was set by the user and moveSlides is less than number of slides showing
568            if (slider.settings.moveSlides > 0 && slider.settings.moveSlides <= getNumberSlidesShowing()) {
569                return slider.settings.moveSlides;
570            }
571            // if moveSlides is 0 (auto)
572            return getNumberSlidesShowing();
573        };
574
575        /**
576         * Sets the slider's (el) left or top position
577         */
578        var setSlidePosition = function () {
579            var position, lastChild, lastShowingIndex;
580            // if last slide, not infinite loop, and number of children is larger than specified maxSlides
581            if (slider.children.length > slider.settings.maxSlides && slider.active.last && !slider.settings.infiniteLoop) {
582                if (slider.settings.mode === 'horizontal') {
583                    // get the last child's position
584                    lastChild = slider.children.last();
585                    position = lastChild.position();
586                    // set the left position
587                    setPositionProperty(-(position.left - (slider.viewport.width() - lastChild.outerWidth())), 'reset', 0);
588                } else if (slider.settings.mode === 'vertical') {
589                    // get the last showing index's position
590                    lastShowingIndex = slider.children.length - slider.settings.minSlides;
591                    position = slider.children.eq(lastShowingIndex).position();
592                    // set the top position
593                    setPositionProperty(-position.top, 'reset', 0);
594                }
595                // if not last slide
596            } else {
597                // get the position of the first showing slide
598                position = slider.children.eq(slider.active.index * getMoveBy()).position();
599                // check for last slide
600                if (slider.active.index === getPagerQty() - 1) {
601                    slider.active.last = true;
602                }
603                // set the respective position
604                if (position !== undefined) {
605                    if (slider.settings.mode === 'horizontal') {
606                        setPositionProperty(-position.left, 'reset', 0);
607                    } else if (slider.settings.mode === 'vertical') {
608                        setPositionProperty(-position.top, 'reset', 0);
609                    }
610                }
611            }
612        };
613
614        /**
615         * Sets the el's animating property position (which in turn will sometimes animate el).
616         * If using CSS, sets the transform property. If not using CSS, sets the top / left property.
617         *
618         * @param value (int)
619         *  - the animating property's value
620         *
621         * @param type (string) 'slide', 'reset', 'ticker'
622         *  - the type of instance for which the function is being
623         *
624         * @param duration (int)
625         *  - the amount of time (in ms) the transition should occupy
626         *
627         * @param params (array) optional
628         *  - an optional parameter containing any variables that need to be passed in
629         */
630        var setPositionProperty = function (value, type, duration, params) {
631            var animateObj, propValue;
632            // use CSS transform
633            if (slider.usingCSS) {
634                // determine the translate3d value
635                propValue = slider.settings.mode === 'vertical' ? 'translate3d(0, ' + value + 'px, 0)' : 'translate3d(' + value + 'px, 0, 0)';
636                // add the CSS transition-duration
637                el.css('-' + slider.cssPrefix + '-transition-duration', duration / 1000 + 's');
638                if (type === 'slide') {
639                    // set the property value
640                    el.css(slider.animProp, propValue);
641                    if (duration !== 0) {
642                        // add a callback method - executes when CSS transition completes
643                        el.on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function (e) {
644                            //make sure it's the correct one
645                            if (!$(e.target).is(el)) {
646                                return;
647                            }
648                            // remove the callback
649                            el.off('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd');
650                            updateAfterSlideTransition();
651                        });
652                    } else { //duration = 0
653                        updateAfterSlideTransition();
654                    }
655                } else if (type === 'reset') {
656                    el.css(slider.animProp, propValue);
657                } else if (type === 'ticker') {
658                    // make the transition use 'linear'
659                    el.css('-' + slider.cssPrefix + '-transition-timing-function', 'linear');
660                    el.css(slider.animProp, propValue);
661                    if (duration !== 0) {
662                        el.on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function (e) {
663                            //make sure it's the correct one
664                            if (!$(e.target).is(el)) {
665                                return;
666                            }
667                            // remove the callback
668                            el.off('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd');
669                            // reset the position
670                            setPositionProperty(params.resetValue, 'reset', 0);
671                            // start the loop again
672                            tickerLoop();
673                        });
674                    } else { //duration = 0
675                        setPositionProperty(params.resetValue, 'reset', 0);
676                        tickerLoop();
677                    }
678                }
679                // use JS animate
680            } else {
681                animateObj = {};
682                animateObj[slider.animProp] = value;
683                if (type === 'slide') {
684                    el.animate(animateObj, duration, slider.settings.easing, function () {
685                        updateAfterSlideTransition();
686                    });
687                } else if (type === 'reset') {
688                    el.css(slider.animProp, value);
689                } else if (type === 'ticker') {
690                    el.animate(animateObj, duration, 'linear', function () {
691                        setPositionProperty(params.resetValue, 'reset', 0);
692                        // run the recursive loop after animation
693                        tickerLoop();
694                    });
695                }
696            }
697        };
698
699        /**
700         * Populates the pager with proper amount of pages
701         */
702        var populatePager = function () {
703            var pagerHtml = '',
704                linkContent = '',
705                pagerQty = getPagerQty();
706            // loop through each pager item
707            for (var i = 0; i < pagerQty; i++) {
708                linkContent = '';
709                // if a buildPager function is supplied, use it to get pager link value, else use index + 1
710                if (slider.settings.buildPager && $.isFunction(slider.settings.buildPager) || slider.settings.pagerCustom) {
711                    linkContent = slider.settings.buildPager(i);
712                    slider.pagerEl.addClass('bx-custom-pager');
713                } else {
714                    linkContent = i + 1;
715                    slider.pagerEl.addClass('bx-default-pager');
716                }
717                // var linkContent = slider.settings.buildPager && $.isFunction(slider.settings.buildPager) ? slider.settings.buildPager(i) : i + 1;
718                // add the markup to the string
719                pagerHtml += '<div class="bx-pager-item"><a href="" data-slide-index="' + i + '" class="bx-pager-link">' + linkContent + '</a></div>';
720            }
721            // populate the pager element with pager links
722            slider.pagerEl.html(pagerHtml);
723        };
724
725        /**
726         * Appends the pager to the controls element
727         */
728        var appendPager = function () {
729            if (!slider.settings.pagerCustom) {
730                // create the pager DOM element
731                slider.pagerEl = $('<div class="bx-pager" />');
732                // if a pager selector was supplied, populate it with the pager
733                if (slider.settings.pagerSelector) {
734                    $(slider.settings.pagerSelector).html(slider.pagerEl);
735                    // if no pager selector was supplied, add it after the wrapper
736                } else {
737                    slider.controls.el.addClass('bx-has-pager').append(slider.pagerEl);
738                }
739                // populate the pager
740                populatePager();
741            } else {
742                slider.pagerEl = $(slider.settings.pagerCustom);
743            }
744            // assign the pager click binding
745            slider.pagerEl.on('click touchend', 'a', clickPagerBind);
746        };
747
748        /**
749         * Appends prev / next controls to the controls element
750         */
751        var appendControls = function () {
752
753            slider.controls.next = $('<a class="bx-next" href="">' + slider.settings.nextText + '</a>');
754            slider.controls.prev = $('<a class="bx-prev" href="">' + slider.settings.prevText + '</a>');
755            // add click actions to the controls
756            slider.controls.next.on('click touchend', clickNextBind);
757            slider.controls.prev.on('click touchend', clickPrevBind);
758
759            // if nextSelector was supplied, populate it
760            if (slider.settings.nextSelector) {
761                $(slider.settings.nextSelector).append(slider.controls.next);
762
763/*                let nextSelector = document.querySelector(slider.settings.nextSelector)
764                if (nextSelector) {
765                    nextSelector.addEventListener('click', clickNextBind);
766                }*/
767            }
768            // if prevSelector was supplied, populate it
769
770            if (slider.settings.prevSelector) {
771                $(slider.settings.prevSelector).append(slider.controls.prev);
772
773 /*               let prevSelector = document.querySelector(slider.settings.prevSelector)
774                if (prevSelector) {
775                    prevSelector.addEventListener('click', clickPrevBind);
776                }*/
777            }
778            // if no custom selectors were supplied
779            if (!slider.settings.nextSelector && !slider.settings.prevSelector) {
780                // add the controls to the DOM
781                slider.controls.directionEl = $('<div class="bx-controls-direction" />');
782                // add the control elements to the directionEl
783                slider.controls.directionEl.append(slider.controls.prev).append(slider.controls.next);
784                // slider.viewport.append(slider.controls.directionEl);
785                slider.controls.el.addClass('bx-has-controls-direction').append(slider.controls.directionEl);
786            }
787        };
788
789        /**
790         * Appends start / stop auto controls to the controls element
791         */
792        var appendControlsAuto = function () {
793            slider.controls.start = $('<div class="bx-controls-auto-item"><a class="bx-start" href="">' + slider.settings.startText + '</a></div>');
794            slider.controls.stop = $('<div class="bx-controls-auto-item"><a class="bx-stop" href="">' + slider.settings.stopText + '</a></div>');
795            // add the controls to the DOM
796            slider.controls.autoEl = $('<div class="bx-controls-auto" />');
797            // on click actions to the controls
798            slider.controls.autoEl.on('click', '.bx-start', clickStartBind);
799            slider.controls.autoEl.on('click', '.bx-stop', clickStopBind);
800            // if autoControlsCombine, insert only the "start" control
801            if (slider.settings.autoControlsCombine) {
802                slider.controls.autoEl.append(slider.controls.start);
803                // if autoControlsCombine is false, insert both controls
804            } else {
805                slider.controls.autoEl.append(slider.controls.start).append(slider.controls.stop);
806            }
807            // if auto controls selector was supplied, populate it with the controls
808            if (slider.settings.autoControlsSelector) {
809                $(slider.settings.autoControlsSelector).html(slider.controls.autoEl);
810                // if auto controls selector was not supplied, add it after the wrapper
811            } else {
812                slider.controls.el.addClass('bx-has-controls-auto').append(slider.controls.autoEl);
813            }
814            // update the auto controls
815            updateAutoControls(slider.settings.autoStart ? 'stop' : 'start');
816        };
817
818        /**
819         * Appends image captions to the DOM
820         */
821        var appendCaptions = function () {
822            // cycle through each child
823            slider.children.each(function (index) {
824                // get the image title attribute
825                var title = $(this).find('img:first').attr('title');
826                // append the caption
827                if (title !== undefined && ('' + title).length) {
828                    $(this).append('<div class="bx-caption"><span>' + title + '</span></div>');
829                }
830            });
831        };
832
833        /**
834         * Click next binding
835         *
836         * @param e (event)
837         *  - DOM event object
838         */
839        var clickNextBind = function (e) {
840            e.preventDefault();
841            if (slider.controls.el.hasClass('disabled')) {
842                return;
843            }
844            // if auto show is running, stop it
845            if (slider.settings.auto && slider.settings.stopAutoOnClick) {
846                el.stopAuto();
847            }
848            el.goToNextSlide();
849        };
850
851        /**
852         * Click prev binding
853         *
854         * @param e (event)
855         *  - DOM event object
856         */
857        var clickPrevBind = function (e) {
858            e.preventDefault();
859            if (slider.controls.el.hasClass('disabled')) {
860                return;
861            }
862            // if auto show is running, stop it
863            if (slider.settings.auto && slider.settings.stopAutoOnClick) {
864                el.stopAuto();
865            }
866            el.goToPrevSlide();
867        };
868
869        /**
870         * Click start binding
871         *
872         * @param e (event)
873         *  - DOM event object
874         */
875        var clickStartBind = function (e) {
876            el.startAuto();
877            e.preventDefault();
878        };
879
880        /**
881         * Click stop binding
882         *
883         * @param e (event)
884         *  - DOM event object
885         */
886        var clickStopBind = function (e) {
887            el.stopAuto();
888            e.preventDefault();
889        };
890
891        /**
892         * Click pager binding
893         *
894         * @param e (event)
895         *  - DOM event object
896         */
897        var clickPagerBind = function (e) {
898            var pagerLink, pagerIndex;
899            e.preventDefault();
900            if (slider.controls.el.hasClass('disabled')) {
901                return;
902            }
903            // if auto show is running, stop it
904            if (slider.settings.auto && slider.settings.stopAutoOnClick) {
905                el.stopAuto();
906            }
907            pagerLink = $(e.currentTarget);
908            if (pagerLink.attr('data-slide-index') !== undefined) {
909                pagerIndex = parseInt(pagerLink.attr('data-slide-index'));
910                // if clicked pager link is not active, continue with the goToSlide call
911                if (pagerIndex !== slider.active.index) {
912                    el.goToSlide(pagerIndex);
913                }
914            }
915        };
916
917        /**
918         * Updates the pager links with an active class
919         *
920         * @param slideIndex (int)
921         *  - index of slide to make active
922         */
923        var updatePagerActive = function (slideIndex) {
924            // if "short" pager type
925            var len = slider.children.length; // nb of children
926            if (slider.settings.pagerType === 'short') {
927                if (slider.settings.maxSlides > 1) {
928                    len = Math.ceil(slider.children.length / slider.settings.maxSlides);
929                }
930                slider.pagerEl.html((slideIndex + 1) + slider.settings.pagerShortSeparator + len);
931                return;
932            }
933            // remove all pager active classes
934            slider.pagerEl.find('a').removeClass('active');
935            // apply the active class for all pagers
936            slider.pagerEl.each(function (i, el) {
937                $(el).find('a').eq(slideIndex).addClass('active');
938            });
939        };
940
941        /**
942         * Performs needed actions after a slide transition
943         */
944        var updateAfterSlideTransition = function () {
945            // if infinite loop is true
946            if (slider.settings.infiniteLoop) {
947                var position = '';
948                // first slide
949                if (slider.active.index === 0) {
950                    // set the new position
951                    position = slider.children.eq(0).position();
952                    // carousel, last slide
953                } else if (slider.active.index === getPagerQty() - 1 && slider.carousel) {
954                    position = slider.children.eq((getPagerQty() - 1) * getMoveBy()).position();
955                    // last slide
956                } else if (slider.active.index === slider.children.length - 1) {
957                    position = slider.children.eq(slider.children.length - 1).position();
958                }
959                if (position) {
960                    if (slider.settings.mode === 'horizontal') {
961                        setPositionProperty(-position.left, 'reset', 0);
962                    } else if (slider.settings.mode === 'vertical') {
963                        setPositionProperty(-position.top, 'reset', 0);
964                    }
965                }
966            }
967            // declare that the transition is complete
968            slider.working = false;
969            // onSlideAfter callback
970            slider.settings.onSlideAfter.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index);
971        };
972
973        /**
974         * Updates the auto controls state (either active, or combined switch)
975         *
976         * @param state (string) "start", "stop"
977         *  - the new state of the auto show
978         */
979        var updateAutoControls = function (state) {
980            // if autoControlsCombine is true, replace the current control with the new state
981            if (slider.settings.autoControlsCombine) {
982                slider.controls.autoEl.html(slider.controls[state]);
983                // if autoControlsCombine is false, apply the "active" class to the appropriate control
984            } else {
985                slider.controls.autoEl.find('a').removeClass('active');
986                slider.controls.autoEl.find('a:not(.bx-' + state + ')').addClass('active');
987            }
988        };
989
990        /**
991         * Updates the direction controls (checks if either should be hidden)
992         */
993        var updateDirectionControls = function () {
994            if (getPagerQty() === 1) {
995                slider.controls.prev.addClass('disabled');
996                slider.controls.next.addClass('disabled');
997            } else if (!slider.settings.infiniteLoop && slider.settings.hideControlOnEnd) {
998                // if first slide
999                if (slider.active.index === 0) {
1000                    slider.controls.prev.addClass('disabled');
1001                    slider.controls.next.removeClass('disabled');
1002                    // if last slide
1003                } else if (slider.active.index === getPagerQty() - 1) {
1004                    slider.controls.next.addClass('disabled');
1005                    slider.controls.prev.removeClass('disabled');
1006                    // if any slide in the middle
1007                } else {
1008                    slider.controls.prev.removeClass('disabled');
1009                    slider.controls.next.removeClass('disabled');
1010                }
1011            }
1012        };
1013        /* auto start and stop functions */
1014        var windowFocusHandler = function () {
1015            el.startAuto();
1016        };
1017        var windowBlurHandler = function () {
1018            el.stopAuto();
1019        };
1020        /**
1021         * Initializes the auto process
1022         */
1023        var initAuto = function () {
1024            // if autoDelay was supplied, launch the auto show using a setTimeout() call
1025            if (slider.settings.autoDelay > 0) {
1026                setTimeout(el.startAuto, slider.settings.autoDelay);
1027                // if autoDelay was not supplied, start the auto show normally
1028            } else {
1029                el.startAuto();
1030
1031                //add focus and blur events to ensure its running if timeout gets paused
1032                $(window).focus(windowFocusHandler).blur(windowBlurHandler);
1033            }
1034            // if autoHover is requested
1035            if (slider.settings.autoHover) {
1036                // on el hover
1037                el.hover(function () {
1038                    // if the auto show is currently playing (has an active interval)
1039                    if (slider.interval) {
1040                        // stop the auto show and pass true argument which will prevent control update
1041                        el.stopAuto(true);
1042                        // create a new autoPaused value which will be used by the relative "mouseout" event
1043                        slider.autoPaused = true;
1044                    }
1045                }, function () {
1046                    // if the autoPaused value was created be the prior "mouseover" event
1047                    if (slider.autoPaused) {
1048                        // start the auto show and pass true argument which will prevent control update
1049                        el.startAuto(true);
1050                        // reset the autoPaused value
1051                        slider.autoPaused = null;
1052                    }
1053                });
1054            }
1055        };
1056
1057        /**
1058         * Initializes the ticker process
1059         */
1060        var initTicker = function () {
1061            var startPosition = 0,
1062                position, transform, value, idx, ratio, property, newSpeed, totalDimens;
1063            // if autoDirection is "next", append a clone of the entire slider
1064            if (slider.settings.autoDirection === 'next') {
1065                el.append(slider.children.clone().addClass('bx-clone'));
1066                // if autoDirection is "prev", prepend a clone of the entire slider, and set the left position
1067            } else {
1068                el.prepend(slider.children.clone().addClass('bx-clone'));
1069                position = slider.children.first().position();
1070                startPosition = slider.settings.mode === 'horizontal' ? -position.left : -position.top;
1071            }
1072            setPositionProperty(startPosition, 'reset', 0);
1073            // do not allow controls in ticker mode
1074            slider.settings.pager = false;
1075            slider.settings.controls = false;
1076            slider.settings.autoControls = false;
1077            // if autoHover is requested
1078            if (slider.settings.tickerHover) {
1079                if (slider.usingCSS) {
1080                    idx = slider.settings.mode === 'horizontal' ? 4 : 5;
1081                    slider.viewport.hover(function () {
1082                        transform = el.css('-' + slider.cssPrefix + '-transform');
1083                        value = parseFloat(transform.split(',')[idx]);
1084                        setPositionProperty(value, 'reset', 0);
1085                    }, function () {
1086                        totalDimens = 0;
1087                        slider.children.each(function (index) {
1088                            totalDimens += slider.settings.mode === 'horizontal' ? $(this).outerWidth(true) : $(this).outerHeight(true);
1089                        });
1090                        // calculate the speed ratio (used to determine the new speed to finish the paused animation)
1091                        ratio = slider.settings.speed / totalDimens;
1092                        // determine which property to use
1093                        property = slider.settings.mode === 'horizontal' ? 'left' : 'top';
1094                        // calculate the new speed
1095                        newSpeed = ratio * (totalDimens - (Math.abs(parseInt(value))));
1096                        tickerLoop(newSpeed);
1097                    });
1098                } else {
1099                    // on el hover
1100                    slider.viewport.hover(function () {
1101                        el.stop();
1102                    }, function () {
1103                        // calculate the total width of children (used to calculate the speed ratio)
1104                        totalDimens = 0;
1105                        slider.children.each(function (index) {
1106                            totalDimens += slider.settings.mode === 'horizontal' ? $(this).outerWidth(true) : $(this).outerHeight(true);
1107                        });
1108                        // calculate the speed ratio (used to determine the new speed to finish the paused animation)
1109                        ratio = slider.settings.speed / totalDimens;
1110                        // determine which property to use
1111                        property = slider.settings.mode === 'horizontal' ? 'left' : 'top';
1112                        // calculate the new speed
1113                        newSpeed = ratio * (totalDimens - (Math.abs(parseInt(el.css(property)))));
1114                        tickerLoop(newSpeed);
1115                    });
1116                }
1117            }
1118            // start the ticker loop
1119            tickerLoop();
1120        };
1121
1122        /**
1123         * Runs a continuous loop, news ticker-style
1124         */
1125        var tickerLoop = function (resumeSpeed) {
1126            var speed = resumeSpeed ? resumeSpeed : slider.settings.speed,
1127                position = {left: 0, top: 0},
1128                reset = {left: 0, top: 0},
1129                animateProperty, resetValue, params;
1130
1131            // if "next" animate left position to last child, then reset left to 0
1132            if (slider.settings.autoDirection === 'next') {
1133                position = el.find('.bx-clone').first().position();
1134                // if "prev" animate left position to 0, then reset left to first non-clone child
1135            } else {
1136                reset = slider.children.first().position();
1137            }
1138            animateProperty = slider.settings.mode === 'horizontal' ? -position.left : -position.top;
1139            resetValue = slider.settings.mode === 'horizontal' ? -reset.left : -reset.top;
1140            params = {resetValue: resetValue};
1141            setPositionProperty(animateProperty, 'ticker', speed, params);
1142        };
1143
1144        /**
1145         * Check if el is on screen
1146         */
1147        var isOnScreen = function (el) {
1148            var win = $(window),
1149                viewport = {
1150                    top: win.scrollTop(),
1151                    left: win.scrollLeft()
1152                },
1153                bounds = el.offset();
1154
1155            viewport.right = viewport.left + win.width();
1156            viewport.bottom = viewport.top + win.height();
1157            bounds.right = bounds.left + el.outerWidth();
1158            bounds.bottom = bounds.top + el.outerHeight();
1159
1160            return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
1161        };
1162
1163        /**
1164         * Initializes keyboard events
1165         */
1166        var keyPress = function (e) {
1167            var activeElementTag = document.activeElement.tagName.toLowerCase(),
1168                tagFilters = 'input|textarea',
1169                p = new RegExp(activeElementTag, ['i']),
1170                result = p.exec(tagFilters);
1171
1172            if (result == null && isOnScreen(el)) {
1173                if (e.keyCode === 39) {
1174                    clickNextBind(e);
1175                    return false;
1176                } else if (e.keyCode === 37) {
1177                    clickPrevBind(e);
1178                    return false;
1179                }
1180            }
1181        };
1182
1183        /**
1184         * Initializes touch events
1185         */
1186        var initTouch = function () {
1187            // initialize object to contain all touch values
1188            slider.touch = {
1189                start: {x: 0, y: 0},
1190                end: {x: 0, y: 0}
1191            };
1192            slider.viewport.on('touchstart MSPointerDown pointerdown', onTouchStart);
1193
1194            //for browsers that have implemented pointer events and fire a click after
1195            //every pointerup regardless of whether pointerup is on same screen location as pointerdown or not
1196            slider.viewport.on('click', '.bxslider a', function (e) {
1197                if (slider.viewport.hasClass('click-disabled')) {
1198                    e.preventDefault();
1199                    slider.viewport.removeClass('click-disabled');
1200                }
1201            });
1202        };
1203
1204        /**
1205         * Event handler for "touchstart"
1206         *
1207         * @param e (event)
1208         *  - DOM event object
1209         */
1210        var onTouchStart = function (e) {
1211            // watch only for left mouse, touch contact and pen contact
1212            // touchstart event object doesn`t have button property
1213            if (e.type !== 'touchstart' && e.button !== 0) {
1214                return;
1215            }
1216            e.preventDefault();
1217            //disable slider controls while user is interacting with slides to avoid slider freeze that happens on touch devices when a slide swipe happens immediately after interacting with slider controls
1218            slider.controls.el.addClass('disabled');
1219
1220            if (slider.working) {
1221                slider.controls.el.removeClass('disabled');
1222            } else {
1223                // record the original position when touch starts
1224                slider.touch.originalPos = el.position();
1225                var orig = e.originalEvent,
1226                    touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig];
1227                var chromePointerEvents = typeof PointerEvent === 'function';
1228                if (chromePointerEvents) {
1229                    if (orig.pointerId === undefined) {
1230                        return;
1231                    }
1232                }
1233                // record the starting touch x, y coordinates
1234                slider.touch.start.x = touchPoints[0].pageX;
1235                slider.touch.start.y = touchPoints[0].pageY;
1236
1237                if (slider.viewport.get(0).setPointerCapture) {
1238                    slider.pointerId = orig.pointerId;
1239                    slider.viewport.get(0).setPointerCapture(slider.pointerId);
1240                }
1241                // store original event data for click fixation
1242                slider.originalClickTarget = orig.originalTarget || orig.target;
1243                slider.originalClickButton = orig.button;
1244                slider.originalClickButtons = orig.buttons;
1245                slider.originalEventType = orig.type;
1246                // at this moment we don`t know what it is click or swipe
1247                slider.hasMove = false;
1248                // on a "touchmove" event to the viewport
1249                slider.viewport.on('touchmove MSPointerMove pointermove', onTouchMove);
1250                // on a "touchend" event to the viewport
1251                slider.viewport.on('touchend MSPointerUp pointerup', onTouchEnd);
1252                slider.viewport.on('MSPointerCancel pointercancel', onPointerCancel);
1253            }
1254        };
1255
1256        /**
1257         * Cancel Pointer for Windows Phone
1258         *
1259         * @param e (event)
1260         *  - DOM event object
1261         */
1262        var onPointerCancel = function (e) {
1263            e.preventDefault();
1264            /* onPointerCancel handler is needed to deal with situations when a touchend
1265            doesn't fire after a touchstart (this happens on windows phones only) */
1266            setPositionProperty(slider.touch.originalPos.left, 'reset', 0);
1267
1268            //remove handlers
1269            slider.controls.el.removeClass('disabled');
1270            slider.viewport.off('MSPointerCancel pointercancel', onPointerCancel);
1271            slider.viewport.off('touchmove MSPointerMove pointermove', onTouchMove);
1272            slider.viewport.off('touchend MSPointerUp pointerup', onTouchEnd);
1273            if (slider.viewport.get(0).releasePointerCapture) {
1274                slider.viewport.get(0).releasePointerCapture(slider.pointerId);
1275            }
1276        };
1277
1278        /**
1279         * Event handler for "touchmove"
1280         *
1281         * @param e (event)
1282         *  - DOM event object
1283         */
1284        var onTouchMove = function (e) {
1285            var orig = e.originalEvent,
1286                touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig],
1287                // if scrolling on y axis, do not prevent default
1288                xMovement = Math.abs(touchPoints[0].pageX - slider.touch.start.x),
1289                yMovement = Math.abs(touchPoints[0].pageY - slider.touch.start.y),
1290                value = 0,
1291                change = 0;
1292            // this is swipe
1293            slider.hasMove = true;
1294
1295            // x axis swipe
1296            if ((xMovement * 3) > yMovement && slider.settings.preventDefaultSwipeX) {
1297                e.preventDefault();
1298                // y axis swipe
1299            } else if ((yMovement * 3) > xMovement && slider.settings.preventDefaultSwipeY) {
1300                e.preventDefault();
1301            }
1302            if (e.type !== 'touchmove') {
1303                e.preventDefault();
1304            }
1305
1306            if (slider.settings.mode !== 'fade' && slider.settings.oneToOneTouch) {
1307                // if horizontal, drag along x axis
1308                if (slider.settings.mode === 'horizontal') {
1309                    change = touchPoints[0].pageX - slider.touch.start.x;
1310                    value = slider.touch.originalPos.left + change;
1311                    // if vertical, drag along y axis
1312                } else {
1313                    change = touchPoints[0].pageY - slider.touch.start.y;
1314                    value = slider.touch.originalPos.top + change;
1315                }
1316                setPositionProperty(value, 'reset', 0);
1317            }
1318        };
1319
1320        /**
1321         * Event handler for "touchend"
1322         *
1323         * @param e (event)
1324         *  - DOM event object
1325         */
1326        var onTouchEnd = function (e) {
1327            e.preventDefault();
1328            slider.viewport.off('touchmove MSPointerMove pointermove', onTouchMove);
1329            //enable slider controls as soon as user stops interacing with slides
1330            slider.controls.el.removeClass('disabled');
1331            var orig = e.originalEvent,
1332                touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig],
1333                value = 0,
1334                distance = 0;
1335            // record end x, y positions
1336            slider.touch.end.x = touchPoints[0].pageX;
1337            slider.touch.end.y = touchPoints[0].pageY;
1338            // if fade mode, check if absolute x distance clears the threshold
1339            if (slider.settings.mode === 'fade') {
1340                distance = Math.abs(slider.touch.start.x - slider.touch.end.x);
1341                if (distance >= slider.settings.swipeThreshold) {
1342                    if (slider.touch.start.x > slider.touch.end.x) {
1343                        el.goToNextSlide();
1344                    } else {
1345                        el.goToPrevSlide();
1346                    }
1347                    el.stopAuto();
1348                }
1349                // not fade mode
1350            } else {
1351                // calculate distance and el's animate property
1352                if (slider.settings.mode === 'horizontal') {
1353                    distance = slider.touch.end.x - slider.touch.start.x;
1354                    value = slider.touch.originalPos.left;
1355                } else {
1356                    distance = slider.touch.end.y - slider.touch.start.y;
1357                    value = slider.touch.originalPos.top;
1358                }
1359                // if not infinite loop and first / last slide, do not attempt a slide transition
1360                if (!slider.settings.infiniteLoop && ((slider.active.index === 0 && distance > 0) || (slider.active.last && distance < 0))) {
1361                    setPositionProperty(value, 'reset', 200);
1362                } else {
1363                    // check if distance clears threshold
1364                    if (Math.abs(distance) >= slider.settings.swipeThreshold) {
1365                        if (distance < 0) {
1366                            el.goToNextSlide();
1367                        } else {
1368                            el.goToPrevSlide();
1369                        }
1370                        el.stopAuto();
1371                    } else {
1372                        // el.animate(property, 200);
1373                        setPositionProperty(value, 'reset', 200);
1374                    }
1375                }
1376            }
1377            slider.viewport.off('touchend MSPointerUp pointerup', onTouchEnd);
1378
1379            if (slider.viewport.get(0).releasePointerCapture) {
1380                slider.viewport.get(0).releasePointerCapture(slider.pointerId);
1381            }
1382            // if slider had swipe with left mouse, touch contact and pen contact
1383            if (slider.hasMove === false && (slider.originalClickButton === 0 || slider.originalEventType === 'touchstart')) {
1384                // trigger click event (fix for Firefox59 and PointerEvent standard compatibility)
1385                $(slider.originalClickTarget).trigger({
1386                    type: 'click',
1387                    button: slider.originalClickButton,
1388                    buttons: slider.originalClickButtons
1389                });
1390            }
1391        };
1392
1393        /**
1394         * Window resize event callback
1395         */
1396        var resizeWindow = function (e) {
1397            // don't do anything if slider isn't initialized.
1398            if (!slider.initialized) {
1399                return;
1400            }
1401            // Delay if slider working.
1402            if (slider.working) {
1403                window.setTimeout(resizeWindow, 10);
1404            } else {
1405                // get the new window dimens (again, thank you IE)
1406                var windowWidthNew = $(window).width(),
1407                    windowHeightNew = $(window).height();
1408                // make sure that it is a true window resize
1409                // *we must check this because our dinosaur friend IE fires a window resize event when certain DOM elements
1410                // are resized. Can you just die already?*
1411                if (windowWidth !== windowWidthNew || windowHeight !== windowHeightNew) {
1412                    // set the new window dimens
1413                    windowWidth = windowWidthNew;
1414                    windowHeight = windowHeightNew;
1415                    // update all dynamic elements
1416                    el.redrawSlider();
1417                    // Call user resize handler
1418                    slider.settings.onSliderResize.call(el, slider.active.index);
1419                }
1420            }
1421        };
1422
1423        /**
1424         * Adds an aria-hidden=true attribute to each element
1425         *
1426         * @param startVisibleIndex (int)
1427         *  - the first visible element's index
1428         */
1429        var applyAriaHiddenAttributes = function (startVisibleIndex) {
1430            var numberOfSlidesShowing = getNumberSlidesShowing();
1431            // only apply attributes if the setting is enabled and not in ticker mode
1432            if (slider.settings.ariaHidden && !slider.settings.ticker) {
1433                // add aria-hidden=true to all elements
1434                slider.children.attr('aria-hidden', 'true');
1435                // get the visible elements and change to aria-hidden=false
1436                slider.children.slice(startVisibleIndex, startVisibleIndex + numberOfSlidesShowing).attr('aria-hidden', 'false');
1437            }
1438        };
1439
1440        /**
1441         * Returns index according to present page range
1442         *
1443         * @param slideOndex (int)
1444         *  - the desired slide index
1445         */
1446        var setSlideIndex = function (slideIndex) {
1447            if (slideIndex < 0) {
1448                if (slider.settings.infiniteLoop) {
1449                    return getPagerQty() - 1;
1450                } else {
1451                    //we don't go to undefined slides
1452                    return slider.active.index;
1453                }
1454                // if slideIndex is greater than children length, set active index to 0 (this happens during infinite loop)
1455            } else if (slideIndex >= getPagerQty()) {
1456                if (slider.settings.infiniteLoop) {
1457                    return 0;
1458                } else {
1459                    //we don't move to undefined pages
1460                    return slider.active.index;
1461                }
1462                // set active index to requested slide
1463            } else {
1464                return slideIndex;
1465            }
1466        };
1467
1468        /**
1469         * ===================================================================================
1470         * = PUBLIC FUNCTIONS
1471         * ===================================================================================
1472         */
1473
1474        /**
1475         * Performs slide transition to the specified slide
1476         *
1477         * @param slideIndex (int)
1478         *  - the destination slide's index (zero-based)
1479         *
1480         * @param direction (string)
1481         *  - INTERNAL USE ONLY - the direction of travel ("prev" / "next")
1482         */
1483        el.goToSlide = function (slideIndex, direction) {
1484            // onSlideBefore, onSlideNext, onSlidePrev callbacks
1485            // Allow transition canceling based on returned value
1486            var performTransition = true,
1487                moveBy = 0,
1488                position = {left: 0, top: 0},
1489                lastChild = null,
1490                lastShowingIndex, eq, value, requestEl;
1491            // store the old index
1492            slider.oldIndex = slider.active.index;
1493            //set new index
1494            slider.active.index = setSlideIndex(slideIndex);
1495
1496            // if plugin is currently in motion, ignore request
1497            if (slider.working || slider.active.index === slider.oldIndex) {
1498                return;
1499            }
1500            // declare that plugin is in motion
1501            slider.working = true;
1502
1503            performTransition = slider.settings.onSlideBefore.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index);
1504
1505            // If transitions canceled, reset and return
1506            if (typeof (performTransition) !== 'undefined' && !performTransition) {
1507                slider.active.index = slider.oldIndex; // restore old index
1508                slider.working = false; // is not in motion
1509                return;
1510            }
1511
1512            if (direction === 'next') {
1513                // Prevent canceling in future functions or lack there-of from negating previous commands to cancel
1514                if (!slider.settings.onSlideNext.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)) {
1515                    performTransition = false;
1516                }
1517            } else if (direction === 'prev') {
1518                // Prevent canceling in future functions or lack there-of from negating previous commands to cancel
1519                if (!slider.settings.onSlidePrev.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)) {
1520                    performTransition = false;
1521                }
1522            }
1523
1524            // check if last slide
1525            slider.active.last = slider.active.index >= getPagerQty() - 1;
1526            // update the pager with active class
1527            if (slider.settings.pager || slider.settings.pagerCustom) {
1528                updatePagerActive(slider.active.index);
1529            }
1530            // // check for direction control update
1531            if (slider.settings.controls) {
1532                updateDirectionControls();
1533            }
1534            // if slider is set to mode: "fade"
1535            if (slider.settings.mode === 'fade') {
1536                // if adaptiveHeight is true and next height is different from current height, animate to the new height
1537                if (slider.settings.adaptiveHeight && slider.viewport.height() !== getViewportHeight()) {
1538                    slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed);
1539                }
1540                // fade out the visible child and reset its z-index value
1541                slider.children.filter(':visible').fadeOut(slider.settings.speed).css({zIndex: 0});
1542                // fade in the newly requested slide
1543                slider.children.eq(slider.active.index).css('zIndex', slider.settings.slideZIndex + 1).fadeIn(slider.settings.speed, function () {
1544                    $(this).css('zIndex', slider.settings.slideZIndex);
1545                    updateAfterSlideTransition();
1546                });
1547                // slider mode is not "fade"
1548            } else {
1549                // if adaptiveHeight is true and next height is different from current height, animate to the new height
1550                if (slider.settings.adaptiveHeight && slider.viewport.height() !== getViewportHeight()) {
1551                    slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed);
1552                }
1553                // if carousel and not infinite loop
1554                if (!slider.settings.infiniteLoop && slider.carousel && slider.active.last) {
1555                    if (slider.settings.mode === 'horizontal') {
1556                        // get the last child position
1557                        lastChild = slider.children.eq(slider.children.length - 1);
1558                        position = lastChild.position();
1559                        // calculate the position of the last slide
1560                        moveBy = slider.viewport.width() - lastChild.outerWidth();
1561                    } else {
1562                        // get last showing index position
1563                        lastShowingIndex = slider.children.length - slider.settings.minSlides;
1564                        position = slider.children.eq(lastShowingIndex).position();
1565                    }
1566                    // horizontal carousel, going previous while on first slide (infiniteLoop mode)
1567                } else if (slider.carousel && slider.active.last && direction === 'prev') {
1568                    // get the last child position
1569                    eq = slider.settings.moveSlides === 1 ? slider.settings.maxSlides - getMoveBy() : ((getPagerQty() - 1) * getMoveBy()) - (slider.children.length - slider.settings.maxSlides);
1570                    lastChild = el.children('.bx-clone').eq(eq);
1571                    position = lastChild.position();
1572                    // if infinite loop and "Next" is clicked on the last slide
1573                } else if (direction === 'next' && slider.active.index === 0) {
1574                    // get the last clone position
1575                    position = el.find('> .bx-clone').eq(slider.settings.maxSlides).position();
1576                    slider.active.last = false;
1577                    // normal non-zero requests
1578                } else if (slideIndex >= 0) {
1579                    //parseInt is applied to allow floats for slides/page
1580                    requestEl = slideIndex * parseInt(getMoveBy());
1581                    position = slider.children.eq(requestEl).position();
1582                }
1583
1584                /* If the position doesn't exist
1585                 * (e.g. if you destroy the slider on a next click),
1586                 * it doesn't throw an error.
1587                 */
1588                if (typeof (position) !== 'undefined') {
1589                    value = slider.settings.mode === 'horizontal' ? -(position.left - moveBy) : -position.top;
1590                    // plugin values to be animated
1591                    setPositionProperty(value, 'slide', slider.settings.speed);
1592                }
1593                slider.working = false;
1594            }
1595            if (slider.settings.ariaHidden) {
1596                applyAriaHiddenAttributes(slider.active.index * getMoveBy());
1597            }
1598        };
1599
1600        /**
1601         * Transitions to the next slide in the show
1602         */
1603        el.goToNextSlide = function () {
1604            // if infiniteLoop is false and last page is showing, disregard call
1605            if (!slider.settings.infiniteLoop && slider.active.last) {
1606                return;
1607            }
1608            if (slider.working === true) {
1609                return;
1610            }
1611            var pagerIndex = parseInt(slider.active.index) + 1;
1612            el.goToSlide(pagerIndex, 'next');
1613        };
1614
1615        /**
1616         * Transitions to the prev slide in the show
1617         */
1618        el.goToPrevSlide = function () {
1619            // if infiniteLoop is false and last page is showing, disregard call
1620            if (!slider.settings.infiniteLoop && slider.active.index === 0) {
1621                return;
1622            }
1623            if (slider.working === true) {
1624                return;
1625            }
1626            var pagerIndex = parseInt(slider.active.index) - 1;
1627            el.goToSlide(pagerIndex, 'prev');
1628        };
1629
1630        /**
1631         * Starts the auto show
1632         *
1633         * @param preventControlUpdate (boolean)
1634         *  - if true, auto controls state will not be updated
1635         */
1636        el.startAuto = function (preventControlUpdate) {
1637            // if an interval already exists, disregard call
1638            if (slider.interval) {
1639                return;
1640            }
1641            // create an interval
1642            slider.interval = setInterval(function () {
1643                if (slider.settings.autoDirection === 'next') {
1644                    el.goToNextSlide();
1645                } else {
1646                    el.goToPrevSlide();
1647                }
1648            }, slider.settings.pause);
1649            //allback for when the auto rotate status changes
1650            slider.settings.onAutoChange.call(el, true);
1651            // if auto controls are displayed and preventControlUpdate is not true
1652            if (slider.settings.autoControls && preventControlUpdate !== true) {
1653                updateAutoControls('stop');
1654            }
1655        };
1656
1657        /**
1658         * Stops the auto show
1659         *
1660         * @param preventControlUpdate (boolean)
1661         *  - if true, auto controls state will not be updated
1662         */
1663        el.stopAuto = function (preventControlUpdate) {
1664            // if slider is auto paused, just clear that state
1665            if (slider.autoPaused) slider.autoPaused = false;
1666            // if no interval exists, disregard call
1667            if (!slider.interval) {
1668                return;
1669            }
1670            // clear the interval
1671            clearInterval(slider.interval);
1672            slider.interval = null;
1673            //allback for when the auto rotate status changes
1674            slider.settings.onAutoChange.call(el, false);
1675            // if auto controls are displayed and preventControlUpdate is not true
1676            if (slider.settings.autoControls && preventControlUpdate !== true) {
1677                updateAutoControls('start');
1678            }
1679        };
1680
1681        /**
1682         * Returns current slide index (zero-based)
1683         */
1684        el.getCurrentSlide = function () {
1685            return slider.active.index;
1686        };
1687
1688        /**
1689         * Returns current slide element
1690         */
1691        el.getCurrentSlideElement = function () {
1692            return slider.children.eq(slider.active.index);
1693        };
1694
1695        /**
1696         * Returns a slide element
1697         * @param index (int)
1698         *  - The index (zero-based) of the element you want returned.
1699         */
1700        el.getSlideElement = function (index) {
1701            return slider.children.eq(index);
1702        };
1703
1704        /**
1705         * Returns number of slides in show
1706         */
1707        el.getSlideCount = function () {
1708            return slider.children.length;
1709        };
1710
1711        /**
1712         * Return slider.working variable
1713         */
1714        el.isWorking = function () {
1715            return slider.working;
1716        };
1717
1718        /**
1719         * Update all dynamic slider elements
1720         */
1721        el.redrawSlider = function () {
1722            // resize all children in ratio to new screen size
1723            slider.children.add(el.find('.bx-clone')).outerWidth(getSlideWidth());
1724            // adjust the height
1725            slider.viewport.css('height', getViewportHeight());
1726            // update the slide position
1727            if (!slider.settings.ticker) {
1728                setSlidePosition();
1729            }
1730            // if active.last was true before the screen resize, we want
1731            // to keep it last no matter what screen size we end on
1732            if (slider.active.last) {
1733                slider.active.index = getPagerQty() - 1;
1734            }
1735            // if the active index (page) no longer exists due to the resize, simply set the index as last
1736            if (slider.active.index >= getPagerQty()) {
1737                slider.active.last = true;
1738            }
1739            // if a pager is being displayed and a custom pager is not being used, update it
1740            if (slider.settings.pager && !slider.settings.pagerCustom) {
1741                populatePager();
1742                updatePagerActive(slider.active.index);
1743            }
1744            if (slider.settings.ariaHidden) {
1745                applyAriaHiddenAttributes(sli
vendor: 2,652 bytes, lines 1745-1822
1745der.active.index * getMoveBy());
1746            }
1747        };
1748
1749        /**
1750         * Destroy the current instance of the slider (revert everything back to original state)
1751         */
1752        el.destroySlider = function () {
1753            // don't do anything if slider has already been destroyed
1754            if (!slider.initialized) {
1755                return;
1756            }
1757            slider.initialized = false;
1758            $('.bx-clone', this).remove();
1759            slider.children.each(function () {
1760                if ($(this).data('origStyle') !== undefined) {
1761                    $(this).attr('style', $(this).data('origStyle'));
1762                } else {
1763                    $(this).removeAttr('style');
1764                }
1765            });
1766            if ($(this).data('origStyle') !== undefined) {
1767                this.attr('style', $(this).data('origStyle'));
1768            } else {
1769                $(this).removeAttr('style');
1770            }
1771            $(this).unwrap().unwrap();
1772            if (slider.controls.el) {
1773                slider.controls.el.remove();
1774            }
1775            if (slider.controls.next) {
1776                slider.controls.next.remove();
1777            }
1778            if (slider.controls.prev) {
1779                slider.controls.prev.remove();
1780            }
1781            if (slider.pagerEl && slider.settings.controls && !slider.settings.pagerCustom) {
1782                slider.pagerEl.remove();
1783            }
1784            $('.bx-caption', this).remove();
1785            if (slider.controls.autoEl) {
1786                slider.controls.autoEl.remove();
1787            }
1788            clearInterval(slider.interval);
1789            if (slider.settings.responsive) {
1790                $(window).off('resize', resizeWindow);
1791            }
1792            if (slider.settings.keyboardEnabled) {
1793                $(document).off('keydown', keyPress);
1794            }
1795            //remove self reference in data
1796            $(this).removeData('bxSlider');
1797            // remove global window handlers
1798            $(window).off('blur', windowBlurHandler).off('focus', windowFocusHandler);
1799        };
1800
1801        /**
1802         * Reload the slider (revert all DOM changes, and re-initialize)
1803         */
1804        el.reloadSlider = function (settings) {
1805            if (settings !== undefined) {
1806                options = settings;
1807            }
1808            el.destroySlider();
1809            init();
1810            //store reference to self in order to access public functions later
1811            $(el).data('bxSlider', this);
1812        };
1813
1814        init();
1815
1816        $(el).data('bxSlider', this);
1817
1818        // returns the current jQuery object
1819        return this;
1820    };
1821
1822})(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.