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