PluginProbe ʕ •ᴥ•ʔ
Strong Testimonials / 3.3.4
Strong Testimonials v3.3.4
3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.0.1 2.30.9 2.31.10 2.32 2.32.1 2.32.2 2.32.3 2.32.4 2.33 2.34 2.35 2.36 2.37 2.38 2.38.1 2.39 2.39.1 2.39.2 2.39.3 2.40.0 2.40.1 2.40.2 2.40.3 2.40.4 2.40.5 2.40.6 2.40.7 2.41.0 2.41.1 2.50.0 2.50.1 2.50.2 2.50.3 2.50.4 2.51.0 2.51.1 2.51.2 2.51.3 2.51.4 2.51.5 2.51.6 2.51.7 2.51.8 2.51.9 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.20 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.17 3.2.18 3.2.19 3.2.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0
strong-testimonials / assets / public / js / lib / strongslider / jquery-strongslider.js
strong-testimonials / assets / public / js / lib / strongslider Last commit date
LICENSE.md 1 year ago jquery-strongslider.js 1 year ago jquery-strongslider.min.js 1 year ago
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