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