js/jquery.flexslider.js   F
last analyzed

Complexity

Total Complexity 445
Complexity/F 5.56

Size

Lines of Code 1190
Function Count 80

Duplication

Duplicated Lines 83
Ratio 6.97 %

Importance

Changes 0
Metric Value
cc 0
eloc 771
nc 0
dl 83
loc 1190
rs 1.829
c 0
b 0
f 0
wmc 445
mnd 8
bc 260
fnc 80
bpm 3.25
cpm 5.5625
noi 29

12 Functions

Rating   Name   Duplication   Size   Complexity  
A $(window).blur 0 3 1
B 83 1189 1
A $(window).focus 0 3 1
A $.flexslider.defaults.start 0 1 1
B $.flexslider 83 1078 1
A $.flexslider.defaults.init 0 1 1
A $.flexslider.defaults.end 0 1 1
A $.flexslider.defaults.added 0 1 1
A $.flexslider.defaults.removed 0 1 1
A $.flexslider.defaults.after 0 1 1
A $.flexslider.defaults.before 0 1 1
C $.fn.flexslider 0 30 11

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like js/jquery.flexslider.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*
2
 * jQuery FlexSlider v2.6.1
3
 * Copyright 2012 WooThemes
4
 * Contributing Author: Tyler Smith
5
 */
6
;
7
(function ($) {
8
9
  var focused = true;
10
11
  //FlexSlider: Object Instance
12
  $.flexslider = function(el, options) {
13
    var slider = $(el);
14
15
    // making variables public
16
    slider.vars = $.extend({}, $.flexslider.defaults, options);
17
18
    var namespace = slider.vars.namespace,
19
        msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture,
20
        touch = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch && document instanceof DocumentTouch) && slider.vars.touch,
21
        // depricating this idea, as devices are being released with both of these events
22
        eventType = "click touchend MSPointerUp keyup",
23
        watchedEvent = "",
24
        watchedEventClearTimer,
25
        vertical = slider.vars.direction === "vertical",
26
        reverse = slider.vars.reverse,
27
        carousel = (slider.vars.itemWidth > 0),
28
        fade = slider.vars.animation === "fade",
29
        asNav = slider.vars.asNavFor !== "",
30
        methods = {};
31
32
    // Store a reference to the slider object
33
    $.data(el, "flexslider", slider);
34
35
    // Private slider methods
36
    methods = {
37
      init: function() {
38
        slider.animating = false;
39
        // Get current slide and make sure it is a number
40
        slider.currentSlide = parseInt( ( slider.vars.startAt ? slider.vars.startAt : 0), 10 );
41
        if ( isNaN( slider.currentSlide ) ) { slider.currentSlide = 0; }
42
        slider.animatingTo = slider.currentSlide;
43
        slider.atEnd = (slider.currentSlide === 0 || slider.currentSlide === slider.last);
44
        slider.containerSelector = slider.vars.selector.substr(0,slider.vars.selector.search(' '));
45
        slider.slides = $(slider.vars.selector, slider);
46
        slider.container = $(slider.containerSelector, slider);
47
        slider.count = slider.slides.length;
48
        // SYNC:
49
        slider.syncExists = $(slider.vars.sync).length > 0;
50
        // SLIDE:
51
        if (slider.vars.animation === "slide") { slider.vars.animation = "swing"; }
52
        slider.prop = (vertical) ? "top" : "marginLeft";
53
        slider.args = {};
54
        // SLIDESHOW:
55
        slider.manualPause = false;
56
        slider.stopped = false;
57
        //PAUSE WHEN INVISIBLE
58
        slider.started = false;
59
        slider.startTimeout = null;
60
        // TOUCH/USECSS:
61
        slider.transitions = !slider.vars.video && !fade && slider.vars.useCSS && (function() {
62
          var obj = document.createElement('div'),
63
              props = ['perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective'];
64
          for (var i in props) {
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
65
            if ( obj.style[ props[i] ] !== undefined ) {
66
              slider.pfx = props[i].replace('Perspective','').toLowerCase();
67
              slider.prop = "-" + slider.pfx + "-transform";
68
              return true;
69
            }
70
          }
71
          return false;
72
        }());
73
        slider.ensureAnimationEnd = '';
74
        // CONTROLSCONTAINER:
75
        if (slider.vars.controlsContainer !== "") slider.controlsContainer = $(slider.vars.controlsContainer).length > 0 && $(slider.vars.controlsContainer);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
76
        // MANUAL:
77
        if (slider.vars.manualControls !== "") slider.manualControls = $(slider.vars.manualControls).length > 0 && $(slider.vars.manualControls);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
78
79
        // CUSTOM DIRECTION NAV:
80
        if (slider.vars.customDirectionNav !== "") slider.customDirectionNav = $(slider.vars.customDirectionNav).length === 2 && $(slider.vars.customDirectionNav);
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
81
82
        // RANDOMIZE:
83
        if (slider.vars.randomize) {
84
          slider.slides.sort(function() { return (Math.round(Math.random())-0.5); });
85
          slider.container.empty().append(slider.slides);
86
        }
87
88
        slider.doMath();
89
90
        // INIT
91
        slider.setup("init");
92
93
        // CONTROLNAV:
94
        if (slider.vars.controlNav) { methods.controlNav.setup(); }
95
96
        // DIRECTIONNAV:
97
        if (slider.vars.directionNav) { methods.directionNav.setup(); }
98
99
        // KEYBOARD:
100
        if (slider.vars.keyboard && ($(slider.containerSelector).length === 1 || slider.vars.multipleKeyboard)) {
101
          $(document).bind('keyup', function(event) {
102
            var keycode = event.keyCode;
103
            if (!slider.animating && (keycode === 39 || keycode === 37)) {
104
              var target = (keycode === 39) ? slider.getTarget('next') :
105
                           (keycode === 37) ? slider.getTarget('prev') : false;
106
              slider.flexAnimate(target, slider.vars.pauseOnAction);
107
            }
108
          });
109
        }
110
        // MOUSEWHEEL:
111
        if (slider.vars.mousewheel) {
112
          slider.bind('mousewheel', function(event, delta, deltaX, deltaY) {
0 ignored issues
show
Unused Code introduced by
The parameter deltaY is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter deltaX is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
113
            event.preventDefault();
114
            var target = (delta < 0) ? slider.getTarget('next') : slider.getTarget('prev');
115
            slider.flexAnimate(target, slider.vars.pauseOnAction);
116
          });
117
        }
118
119
        // PAUSEPLAY
120
        if (slider.vars.pausePlay) { methods.pausePlay.setup(); }
121
122
        //PAUSE WHEN INVISIBLE
123
        if (slider.vars.slideshow && slider.vars.pauseInvisible) { methods.pauseInvisible.init(); }
124
125
        // SLIDSESHOW
126
        if (slider.vars.slideshow) {
127
          if (slider.vars.pauseOnHover) {
128
            slider.hover(function() {
129
              if (!slider.manualPlay && !slider.manualPause) { slider.pause(); }
130
            }, function() {
131
              if (!slider.manualPause && !slider.manualPlay && !slider.stopped) { slider.play(); }
132
            });
133
          }
134
          // initialize animation
135
          //If we're visible, or we don't use PageVisibility API
136
          if(!slider.vars.pauseInvisible || !methods.pauseInvisible.isHidden()) {
137
            (slider.vars.initDelay > 0) ? slider.startTimeout = setTimeout(slider.play, slider.vars.initDelay) : slider.play();
138
          }
139
        }
140
141
        // ASNAV:
142
        if (asNav) { methods.asNav.setup(); }
143
144
        // TOUCH
145
        if (touch && slider.vars.touch) { methods.touch(); }
146
147
        // FADE&&SMOOTHHEIGHT || SLIDE:
148
        if (!fade || (fade && slider.vars.smoothHeight)) { $(window).bind("resize orientationchange focus", methods.resize); }
149
150
        slider.find("img").attr("draggable", "false");
151
152
        // API: start() Callback
153
        setTimeout(function(){
154
          slider.vars.start(slider);
155
        }, 200);
156
      },
157
      asNav: {
158
        setup: function() {
159
          slider.asNav = true;
160
          slider.animatingTo = Math.floor(slider.currentSlide/slider.move);
161
          slider.currentItem = slider.currentSlide;
162
          slider.slides.removeClass(namespace + "active-slide").eq(slider.currentItem).addClass(namespace + "active-slide");
163
          if(!msGesture){
164
              slider.slides.on(eventType, function(e){
165
                e.preventDefault();
166
                var $slide = $(this),
167
                    target = $slide.index();
168
                var posFromLeft = $slide.offset().left - $(slider).scrollLeft(); // Find position of slide relative to left of slider container
169
                if( posFromLeft <= 0 && $slide.hasClass( namespace + 'active-slide' ) ) {
170
                  slider.flexAnimate(slider.getTarget("prev"), true);
171
                } else if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass(namespace + "active-slide")) {
172
                  slider.direction = (slider.currentItem < target) ? "next" : "prev";
173
                  slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true);
174
                }
175
              });
176
          }else{
177
              el._slider = slider;
178
              slider.slides.each(function (){
179
                  var that = this;
180
                  that._gesture = new MSGesture();
181
                  that._gesture.target = that;
182
                  that.addEventListener("MSPointerDown", function (e){
183
                      e.preventDefault();
184
                      if(e.currentTarget._gesture) {
185
                        e.currentTarget._gesture.addPointer(e.pointerId);
186
                      }
187
                  }, false);
188
                  that.addEventListener("MSGestureTap", function (e){
189
                      e.preventDefault();
190
                      var $slide = $(this),
191
                          target = $slide.index();
192
                      if (!$(slider.vars.asNavFor).data('flexslider').animating && !$slide.hasClass('active')) {
193
                          slider.direction = (slider.currentItem < target) ? "next" : "prev";
194
                          slider.flexAnimate(target, slider.vars.pauseOnAction, false, true, true);
195
                      }
196
                  });
197
              });
198
          }
199
        }
200
      },
201
      controlNav: {
202
        setup: function() {
203
          if (!slider.manualControls) {
204
            methods.controlNav.setupPaging();
205
          } else { // MANUALCONTROLS:
206
            methods.controlNav.setupManual();
207
          }
208
        },
209
        setupPaging: function() {
210
          var type = (slider.vars.controlNav === "thumbnails") ? 'control-thumbs' : 'control-paging',
211
              j = 1,
212
              item,
213
              slide;
214
215
          slider.controlNavScaffold = $('<ol class="'+ namespace + 'control-nav ' + namespace + type + '"></ol>');
216
217
          if (slider.pagingCount > 1) {
218
            for (var i = 0; i < slider.pagingCount; i++) {
219
              slide = slider.slides.eq(i);
220
              if ( undefined === slide.attr( 'data-thumb-alt' ) ) { slide.attr( 'data-thumb-alt', '' ); }
221
              var altText = ( '' !== slide.attr( 'data-thumb-alt' ) ) ? altText = ' alt="' + slide.attr( 'data-thumb-alt' ) + '"' : '';
0 ignored issues
show
Unused Code introduced by
The assignment to variable altText seems to be never used. Consider removing it.
Loading history...
222
              item = (slider.vars.controlNav === "thumbnails") ? '<img src="' + slide.attr( 'data-thumb' ) + '"' + altText + '/>' : '<a href="#">' + j + '</a>';
223
              if ( 'thumbnails' === slider.vars.controlNav && true === slider.vars.thumbCaptions ) {
224
                var captn = slide.attr( 'data-thumbcaption' );
225
                if ( '' !== captn && undefined !== captn ) { item += '<span class="' + namespace + 'caption">' + captn + '</span>'; }
226
              }
227
              slider.controlNavScaffold.append('<li>' + item + '</li>');
228
              j++;
229
            }
230
          }
231
232
          // CONTROLSCONTAINER:
233
          (slider.controlsContainer) ? $(slider.controlsContainer).append(slider.controlNavScaffold) : slider.append(slider.controlNavScaffold);
234
          methods.controlNav.set();
235
236
          methods.controlNav.active();
237
238
          slider.controlNavScaffold.delegate('a, img', eventType, function(event) {
239
            event.preventDefault();
240
241
            if (watchedEvent === "" || watchedEvent === event.type) {
242
              var $this = $(this),
243
                  target = slider.controlNav.index($this);
244
245
              if (!$this.hasClass(namespace + 'active')) {
246
                slider.direction = (target > slider.currentSlide) ? "next" : "prev";
247
                slider.flexAnimate(target, slider.vars.pauseOnAction);
248
              }
249
            }
250
251
            // setup flags to prevent event duplication
252
            if (watchedEvent === "") {
253
              watchedEvent = event.type;
254
            }
255
            methods.setToClearWatchedEvent();
256
257
          });
258
        },
259
        setupManual: function() {
260
          slider.controlNav = slider.manualControls;
261
          methods.controlNav.active();
262
263
          slider.controlNav.bind(eventType, function(event) {
264
            event.preventDefault();
265
266
            if (watchedEvent === "" || watchedEvent === event.type) {
267
              var $this = $(this),
268
                  target = slider.controlNav.index($this);
269
270
              if (!$this.hasClass(namespace + 'active')) {
271
                (target > slider.currentSlide) ? slider.direction = "next" : slider.direction = "prev";
272
                slider.flexAnimate(target, slider.vars.pauseOnAction);
273
              }
274
            }
275
276
            // setup flags to prevent event duplication
277
            if (watchedEvent === "") {
278
              watchedEvent = event.type;
279
            }
280
            methods.setToClearWatchedEvent();
281
          });
282
        },
283
        set: function() {
284
          var selector = (slider.vars.controlNav === "thumbnails") ? 'img' : 'a';
285
          slider.controlNav = $('.' + namespace + 'control-nav li ' + selector, (slider.controlsContainer) ? slider.controlsContainer : slider);
286
        },
287
        active: function() {
288
          slider.controlNav.removeClass(namespace + "active").eq(slider.animatingTo).addClass(namespace + "active");
289
        },
290
        update: function(action, pos) {
291
          if (slider.pagingCount > 1 && action === "add") {
292
            slider.controlNavScaffold.append($('<li><a href="#">' + slider.count + '</a></li>'));
293
          } else if (slider.pagingCount === 1) {
294
            slider.controlNavScaffold.find('li').remove();
295
          } else {
296
            slider.controlNav.eq(pos).closest('li').remove();
297
          }
298
          methods.controlNav.set();
299
          (slider.pagingCount > 1 && slider.pagingCount !== slider.controlNav.length) ? slider.update(pos, action) : methods.controlNav.active();
300
        }
301
      },
302
      directionNav: {
303
        setup: function() {
304
          var directionNavScaffold = $('<ul class="' + namespace + 'direction-nav"><li class="' + namespace + 'nav-prev"><a class="' + namespace + 'prev" href="#">' + slider.vars.prevText + '</a></li><li class="' + namespace + 'nav-next"><a class="' + namespace + 'next" href="#">' + slider.vars.nextText + '</a></li></ul>');
305
306
          // CUSTOM DIRECTION NAV:
307
          if (slider.customDirectionNav) {
308
            slider.directionNav = slider.customDirectionNav;
309
          // CONTROLSCONTAINER:
310
          } else if (slider.controlsContainer) {
311
            $(slider.controlsContainer).append(directionNavScaffold);
312
            slider.directionNav = $('.' + namespace + 'direction-nav li a', slider.controlsContainer);
313
          } else {
314
            slider.append(directionNavScaffold);
315
            slider.directionNav = $('.' + namespace + 'direction-nav li a', slider);
316
          }
317
318
          methods.directionNav.update();
319
320
          slider.directionNav.bind(eventType, function(event) {
321
            event.preventDefault();
322
            var target;
323
324
            if (watchedEvent === "" || watchedEvent === event.type) {
325
              target = ($(this).hasClass(namespace + 'next')) ? slider.getTarget('next') : slider.getTarget('prev');
326
              slider.flexAnimate(target, slider.vars.pauseOnAction);
327
            }
328
329
            // setup flags to prevent event duplication
330
            if (watchedEvent === "") {
331
              watchedEvent = event.type;
332
            }
333
            methods.setToClearWatchedEvent();
334
          });
335
        },
336
        update: function() {
337
          var disabledClass = namespace + 'disabled';
338
          if (slider.pagingCount === 1) {
339
            slider.directionNav.addClass(disabledClass).attr('tabindex', '-1');
340
          } else if (!slider.vars.animationLoop) {
341
            if (slider.animatingTo === 0) {
342
              slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "prev").addClass(disabledClass).attr('tabindex', '-1');
343
            } else if (slider.animatingTo === slider.last) {
344
              slider.directionNav.removeClass(disabledClass).filter('.' + namespace + "next").addClass(disabledClass).attr('tabindex', '-1');
345
            } else {
346
              slider.directionNav.removeClass(disabledClass).removeAttr('tabindex');
347
            }
348
          } else {
349
            slider.directionNav.removeClass(disabledClass).removeAttr('tabindex');
350
          }
351
        }
352
      },
353
      pausePlay: {
354
        setup: function() {
355
          var pausePlayScaffold = $('<div class="' + namespace + 'pauseplay"><a href="#"></a></div>');
356
357
          // CONTROLSCONTAINER:
358
          if (slider.controlsContainer) {
359
            slider.controlsContainer.append(pausePlayScaffold);
360
            slider.pausePlay = $('.' + namespace + 'pauseplay a', slider.controlsContainer);
361
          } else {
362
            slider.append(pausePlayScaffold);
363
            slider.pausePlay = $('.' + namespace + 'pauseplay a', slider);
364
          }
365
366
          methods.pausePlay.update((slider.vars.slideshow) ? namespace + 'pause' : namespace + 'play');
367
368
          slider.pausePlay.bind(eventType, function(event) {
369
            event.preventDefault();
370
371
            if (watchedEvent === "" || watchedEvent === event.type) {
372
              if ($(this).hasClass(namespace + 'pause')) {
373
                slider.manualPause = true;
374
                slider.manualPlay = false;
375
                slider.pause();
376
              } else {
377
                slider.manualPause = false;
378
                slider.manualPlay = true;
379
                slider.play();
380
              }
381
            }
382
383
            // setup flags to prevent event duplication
384
            if (watchedEvent === "") {
385
              watchedEvent = event.type;
386
            }
387
            methods.setToClearWatchedEvent();
388
          });
389
        },
390
        update: function(state) {
391
          (state === "play") ? slider.pausePlay.removeClass(namespace + 'pause').addClass(namespace + 'play').html(slider.vars.playText) : slider.pausePlay.removeClass(namespace + 'play').addClass(namespace + 'pause').html(slider.vars.pauseText);
392
        }
393
      },
394
      touch: function() {
395
        var startX,
396
          startY,
397
          offset,
398
          cwidth,
399
          dx,
400
          startT,
401
          onTouchStart,
402
          onTouchMove,
403
          onTouchEnd,
404
          scrolling = false,
405
          localX = 0,
406
          localY = 0,
407
          accDx = 0;
408
409
        if(!msGesture){
410
            onTouchStart = function(e) {
411
              if (slider.animating) {
412
                e.preventDefault();
413
              } else if ( ( window.navigator.msPointerEnabled ) || e.touches.length === 1 ) {
414
                slider.pause();
415
                // CAROUSEL:
416
                cwidth = (vertical) ? slider.h : slider. w;
417
                startT = Number(new Date());
418
                // CAROUSEL:
419
420
                // Local vars for X and Y points.
421
                localX = e.touches[0].pageX;
422
                localY = e.touches[0].pageY;
423
424 View Code Duplication
                offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
425
                         (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
426
                         (carousel && slider.currentSlide === slider.last) ? slider.limit :
427
                         (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide :
428
                         (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth;
429
                startX = (vertical) ? localY : localX;
430
                startY = (vertical) ? localX : localY;
431
432
                el.addEventListener('touchmove', onTouchMove, false);
433
                el.addEventListener('touchend', onTouchEnd, false);
434
              }
435
            };
436
437
            onTouchMove = function(e) {
438
              // Local vars for X and Y points.
439
440
              localX = e.touches[0].pageX;
441
              localY = e.touches[0].pageY;
442
443
              dx = (vertical) ? startX - localY : startX - localX;
444
              scrolling = (vertical) ? (Math.abs(dx) < Math.abs(localX - startY)) : (Math.abs(dx) < Math.abs(localY - startY));
445
446
              var fxms = 500;
447
448 View Code Duplication
              if ( ! scrolling || Number( new Date() ) - startT > fxms ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
449
                e.preventDefault();
450
                if (!fade && slider.transitions) {
451
                  if (!slider.vars.animationLoop) {
452
                    dx = dx/((slider.currentSlide === 0 && dx < 0 || slider.currentSlide === slider.last && dx > 0) ? (Math.abs(dx)/cwidth+2) : 1);
453
                  }
454
                  slider.setProps(offset + dx, "setTouch");
455
                }
456
              }
457
            };
458
459
            onTouchEnd = function(e) {
0 ignored issues
show
Unused Code introduced by
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
460
              // finish the touch by undoing the touch session
461
              el.removeEventListener('touchmove', onTouchMove, false);
462
463 View Code Duplication
              if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
464
                var updateDx = (reverse) ? -dx : dx,
465
                    target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev');
466
467
                if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) {
468
                  slider.flexAnimate(target, slider.vars.pauseOnAction);
469
                } else {
470
                  if (!fade) { slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true); }
471
                }
472
              }
473
              el.removeEventListener('touchend', onTouchEnd, false);
474
475
              startX = null;
476
              startY = null;
477
              dx = null;
478
              offset = null;
479
            };
480
481
            el.addEventListener('touchstart', onTouchStart, false);
482
        }else{
483
            el.style.msTouchAction = "none";
484
            el._gesture = new MSGesture();
485
            el._gesture.target = el;
486
            el.addEventListener("MSPointerDown", onMSPointerDown, false);
487
            el._slider = slider;
488
            el.addEventListener("MSGestureChange", onMSGestureChange, false);
489
            el.addEventListener("MSGestureEnd", onMSGestureEnd, false);
490
491
            function onMSPointerDown(e){
0 ignored issues
show
Bug introduced by
The function onMSPointerDown is declared conditionally. This is not supported by all runtimes. Consider moving it to root scope or using var onMSPointerDown = function() { /* ... */ }; instead.
Loading history...
492
                e.stopPropagation();
493
                if (slider.animating) {
494
                    e.preventDefault();
495
                }else{
496
                    slider.pause();
497
                    el._gesture.addPointer(e.pointerId);
498
                    accDx = 0;
499
                    cwidth = (vertical) ? slider.h : slider. w;
500
                    startT = Number(new Date());
501
                    // CAROUSEL:
502
503 View Code Duplication
                    offset = (carousel && reverse && slider.animatingTo === slider.last) ? 0 :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
504
                        (carousel && reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
505
                            (carousel && slider.currentSlide === slider.last) ? slider.limit :
506
                                (carousel) ? ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.currentSlide :
507
                                    (reverse) ? (slider.last - slider.currentSlide + slider.cloneOffset) * cwidth : (slider.currentSlide + slider.cloneOffset) * cwidth;
508
                }
509
            }
510
511
            function onMSGestureChange(e) {
0 ignored issues
show
Bug introduced by
The function onMSGestureChange is declared conditionally. This is not supported by all runtimes. Consider moving it to root scope or using var onMSGestureChange = function() { /* ... */ }; instead.
Loading history...
512
                e.stopPropagation();
513
                var slider = e.target._slider;
514
                if(!slider){
515
                    return;
516
                }
517
                var transX = -e.translationX,
518
                    transY = -e.translationY;
519
520
                //Accumulate translations.
521
                accDx = accDx + ((vertical) ? transY : transX);
522
                dx = accDx;
523
                scrolling = (vertical) ? (Math.abs(accDx) < Math.abs(-transX)) : (Math.abs(accDx) < Math.abs(-transY));
524
525
                if(e.detail === e.MSGESTURE_FLAG_INERTIA){
526
                    setImmediate(function (){
527
                        el._gesture.stop();
528
                    });
529
530
                    return;
531
                }
532
533 View Code Duplication
                if (!scrolling || Number(new Date()) - startT > 500) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
534
                    e.preventDefault();
535
                    if (!fade && slider.transitions) {
536
                        if (!slider.vars.animationLoop) {
537
                            dx = accDx / ((slider.currentSlide === 0 && accDx < 0 || slider.currentSlide === slider.last && accDx > 0) ? (Math.abs(accDx) / cwidth + 2) : 1);
538
                        }
539
                        slider.setProps(offset + dx, "setTouch");
540
                    }
541
                }
542
            }
543
544
            function onMSGestureEnd(e) {
0 ignored issues
show
Bug introduced by
The function onMSGestureEnd is declared conditionally. This is not supported by all runtimes. Consider moving it to root scope or using var onMSGestureEnd = function() { /* ... */ }; instead.
Loading history...
545
                e.stopPropagation();
546
                var slider = e.target._slider;
547
                if(!slider){
548
                    return;
549
                }
550 View Code Duplication
                if (slider.animatingTo === slider.currentSlide && !scrolling && !(dx === null)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
551
                    var updateDx = (reverse) ? -dx : dx,
552
                        target = (updateDx > 0) ? slider.getTarget('next') : slider.getTarget('prev');
553
554
                    if (slider.canAdvance(target) && (Number(new Date()) - startT < 550 && Math.abs(updateDx) > 50 || Math.abs(updateDx) > cwidth/2)) {
555
                        slider.flexAnimate(target, slider.vars.pauseOnAction);
556
                    } else {
557
                        if (!fade) { slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction, true); }
558
                    }
559
                }
560
561
                startX = null;
562
                startY = null;
563
                dx = null;
564
                offset = null;
565
                accDx = 0;
566
            }
567
        }
568
      },
569
      resize: function() {
570
        if (!slider.animating && slider.is(':visible')) {
571
          if (!carousel) { slider.doMath(); }
572
573
          if (fade) {
574
            // SMOOTH HEIGHT:
575
            methods.smoothHeight();
576
          } else if (carousel) { //CAROUSEL:
577
            slider.slides.width(slider.computedW);
578
            slider.update(slider.pagingCount);
579
            slider.setProps();
580
          }
581
          else if (vertical) { //VERTICAL:
582
            slider.viewport.height(slider.h);
583
            slider.setProps(slider.h, "setTotal");
584
          } else {
585
            // SMOOTH HEIGHT:
586
            if (slider.vars.smoothHeight) { methods.smoothHeight(); }
587
            slider.newSlides.width(slider.computedW);
588
            slider.setProps(slider.computedW, "setTotal");
589
          }
590
        }
591
      },
592
      smoothHeight: function(dur) {
593
        if (!vertical || fade) {
594
          var $obj = (fade) ? slider : slider.viewport;
595
          (dur) ? $obj.animate({"height": slider.slides.eq(slider.animatingTo).innerHeight()}, dur) : $obj.innerHeight(slider.slides.eq(slider.animatingTo).innerHeight());
596
        }
597
      },
598
      sync: function(action) {
599
        var $obj = $(slider.vars.sync).data("flexslider"),
600
            target = slider.animatingTo;
601
602
        switch (action) {
603
          case "animate": $obj.flexAnimate(target, slider.vars.pauseOnAction, false, true); break;
604
          case "play": if (!$obj.playing && !$obj.asNav) { $obj.play(); } break;
605
          case "pause": $obj.pause(); break;
606
        }
607
      },
608
      uniqueID: function($clone) {
609
        // Append _clone to current level and children elements with id attributes
610
        $clone.filter( '[id]' ).add($clone.find( '[id]' )).each(function() {
611
          var $this = $(this);
612
          $this.attr( 'id', $this.attr( 'id' ) + '_clone' );
613
        });
614
        return $clone;
615
      },
616
      pauseInvisible: {
617
        visProp: null,
618
        init: function() {
619
          var visProp = methods.pauseInvisible.getHiddenProp();
620
          if (visProp) {
621
            var evtname = visProp.replace(/[H|h]idden/,'') + 'visibilitychange';
622
            document.addEventListener(evtname, function() {
623
              if (methods.pauseInvisible.isHidden()) {
624
                if(slider.startTimeout) {
625
                  clearTimeout(slider.startTimeout); //If clock is ticking, stop timer and prevent from starting while invisible
626
                } else {
627
                  slider.pause(); //Or just pause
628
                }
629
              }
630
              else {
631
                if(slider.started) {
632
                  slider.play(); //Initiated before, just play
633
                } else {
634
                  if (slider.vars.initDelay > 0) {
635
                    setTimeout(slider.play, slider.vars.initDelay);
636
                  } else {
637
                    slider.play(); //Didn't init before: simply init or wait for it
638
                  }
639
                }
640
              }
641
            });
642
          }
643
        },
644
        isHidden: function() {
645
          var prop = methods.pauseInvisible.getHiddenProp();
646
          if (!prop) {
647
            return false;
648
          }
649
          return document[prop];
650
        },
651
        getHiddenProp: function() {
652
          var prefixes = ['webkit','moz','ms','o'];
653
          // if 'hidden' is natively supported just return it
654
          if ('hidden' in document) {
655
            return 'hidden';
656
          }
657
          // otherwise loop over all the known prefixes until we find one
658
          for ( var i = 0; i < prefixes.length; i++ ) {
659
              if ((prefixes[i] + 'Hidden') in document) {
660
                return prefixes[i] + 'Hidden';
661
              }
662
          }
663
          // otherwise it's not supported
664
          return null;
665
        }
666
      },
667
      setToClearWatchedEvent: function() {
668
        clearTimeout(watchedEventClearTimer);
669
        watchedEventClearTimer = setTimeout(function() {
670
          watchedEvent = "";
671
        }, 3000);
672
      }
673
    };
674
675
    // public methods
676
    slider.flexAnimate = function(target, pause, override, withSync, fromNav) {
677
      if (!slider.vars.animationLoop && target !== slider.currentSlide) {
678
        slider.direction = (target > slider.currentSlide) ? "next" : "prev";
679
      }
680
681
      if (asNav && slider.pagingCount === 1) slider.direction = (slider.currentItem < target) ? "next" : "prev";
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
682
683
      if (!slider.animating && (slider.canAdvance(target, fromNav) || override) && slider.is(":visible")) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if !slider.animating && sli...& slider.is(":visible") is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
684
        if (asNav && withSync) {
685
          var master = $(slider.vars.asNavFor).data('flexslider');
686
          slider.atEnd = target === 0 || target === slider.count - 1;
687
          master.flexAnimate(target, true, false, true, fromNav);
688
          slider.direction = (slider.currentItem < target) ? "next" : "prev";
689
          master.direction = slider.direction;
690
691
          if (Math.ceil((target + 1)/slider.visible) - 1 !== slider.currentSlide && target !== 0) {
692
            slider.currentItem = target;
693
            slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide");
694
            target = Math.floor(target/slider.visible);
695
          } else {
696
            slider.currentItem = target;
697
            slider.slides.removeClass(namespace + "active-slide").eq(target).addClass(namespace + "active-slide");
698
            return false;
699
          }
700
        }
701
702
        slider.animating = true;
703
        slider.animatingTo = target;
704
705
        // SLIDESHOW:
706
        if (pause) { slider.pause(); }
707
708
        // API: before() animation Callback
709
        slider.vars.before(slider);
710
711
        // SYNC:
712
        if (slider.syncExists && !fromNav) { methods.sync("animate"); }
713
714
        // CONTROLNAV
715
        if (slider.vars.controlNav) { methods.controlNav.active(); }
716
717
        // !CAROUSEL:
718
        // CANDIDATE: slide active class (for add/remove slide)
719
        if (!carousel) { slider.slides.removeClass(namespace + 'active-slide').eq(target).addClass(namespace + 'active-slide'); }
720
721
        // INFINITE LOOP:
722
        // CANDIDATE: atEnd
723
        slider.atEnd = target === 0 || target === slider.last;
724
725
        // DIRECTIONNAV:
726
        if (slider.vars.directionNav) { methods.directionNav.update(); }
727
728
        if (target === slider.last) {
729
          // API: end() of cycle Callback
730
          slider.vars.end(slider);
731
          // SLIDESHOW && !INFINITE LOOP:
732
          if (!slider.vars.animationLoop) { slider.pause(); }
733
        }
734
735
        // SLIDE:
736
        if (!fade) {
737
          var dimension = (vertical) ? slider.slides.filter(':first').height() : slider.computedW,
738
              margin, slideString, calcNext;
739
740
          // INFINITE LOOP / REVERSE:
741
          if (carousel) {
742
            margin = slider.vars.itemMargin;
743
            calcNext = ((slider.itemW + margin) * slider.move) * slider.animatingTo;
744
            slideString = (calcNext > slider.limit && slider.visible !== 1) ? slider.limit : calcNext;
745
          } else if (slider.currentSlide === 0 && target === slider.count - 1 && slider.vars.animationLoop && slider.direction !== "next") {
746
            slideString = (reverse) ? (slider.count + slider.cloneOffset) * dimension : 0;
747
          } else if (slider.currentSlide === slider.last && target === 0 && slider.vars.animationLoop && slider.direction !== "prev") {
748
            slideString = (reverse) ? 0 : (slider.count + 1) * dimension;
749
          } else {
750
            slideString = (reverse) ? ((slider.count - 1) - target + slider.cloneOffset) * dimension : (target + slider.cloneOffset) * dimension;
751
          }
752
          slider.setProps(slideString, "", slider.vars.animationSpeed);
753
          if (slider.transitions) {
754
            if (!slider.vars.animationLoop || !slider.atEnd) {
755
              slider.animating = false;
756
              slider.currentSlide = slider.animatingTo;
757
            }
758
759
            // Unbind previous transitionEnd events and re-bind new transitionEnd event
760
            slider.container.unbind("webkitTransitionEnd transitionend");
761
            slider.container.bind("webkitTransitionEnd transitionend", function() {
762
              clearTimeout(slider.ensureAnimationEnd);
763
              slider.wrapup(dimension);
764
            });
765
766
            // Insurance for the ever-so-fickle transitionEnd event
767
            clearTimeout(slider.ensureAnimationEnd);
768
            slider.ensureAnimationEnd = setTimeout(function() {
769
              slider.wrapup(dimension);
770
            }, slider.vars.animationSpeed + 100);
771
772
          } else {
773
            slider.container.animate(slider.args, slider.vars.animationSpeed, slider.vars.easing, function(){
774
              slider.wrapup(dimension);
775
            });
776
          }
777
        } else { // FADE:
778
          if (!touch) {
779
            //slider.slides.eq(slider.currentSlide).fadeOut(slider.vars.animationSpeed, slider.vars.easing);
780
            //slider.slides.eq(target).fadeIn(slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
781
782
            slider.slides.eq(slider.currentSlide).css({"zIndex": 1}).animate({"opacity": 0}, slider.vars.animationSpeed, slider.vars.easing);
783
            slider.slides.eq(target).css({"zIndex": 2}).animate({"opacity": 1}, slider.vars.animationSpeed, slider.vars.easing, slider.wrapup);
784
785
          } else {
786
            slider.slides.eq(slider.currentSlide).css({ "opacity": 0, "zIndex": 1 });
787
            slider.slides.eq(target).css({ "opacity": 1, "zIndex": 2 });
788
            slider.wrapup(dimension);
0 ignored issues
show
Bug introduced by
The variable dimension seems to be never initialized.
Loading history...
789
          }
790
        }
791
        // SMOOTH HEIGHT:
792
        if (slider.vars.smoothHeight) { methods.smoothHeight(slider.vars.animationSpeed); }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
Complexity Best Practice introduced by
There is no return statement if slider.vars.smoothHeight is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
793
      }
794
    };
795
    slider.wrapup = function(dimension) {
796
      // SLIDE:
797
      if (!fade && !carousel) {
798
        if (slider.currentSlide === 0 && slider.animatingTo === slider.last && slider.vars.animationLoop) {
799
          slider.setProps(dimension, "jumpEnd");
800
        } else if (slider.currentSlide === slider.last && slider.animatingTo === 0 && slider.vars.animationLoop) {
801
          slider.setProps(dimension, "jumpStart");
802
        }
803
      }
804
      slider.animating = false;
805
      slider.currentSlide = slider.animatingTo;
806
      // API: after() animation Callback
807
      slider.vars.after(slider);
808
    };
809
810
    // SLIDESHOW:
811
    slider.animateSlides = function() {
812
      if (!slider.animating && focused ) { slider.flexAnimate(slider.getTarget("next")); }
813
    };
814
    // SLIDESHOW:
815
    slider.pause = function() {
816
      clearInterval(slider.animatedSlides);
817
      slider.animatedSlides = null;
818
      slider.playing = false;
819
      // PAUSEPLAY:
820
      if (slider.vars.pausePlay) { methods.pausePlay.update("play"); }
821
      // SYNC:
822
      if (slider.syncExists) { methods.sync("pause"); }
823
    };
824
    // SLIDESHOW:
825
    slider.play = function() {
826
      if (slider.playing) { clearInterval(slider.animatedSlides); }
827
      slider.animatedSlides = slider.animatedSlides || setInterval(slider.animateSlides, slider.vars.slideshowSpeed);
828
      slider.started = slider.playing = true;
829
      // PAUSEPLAY:
830
      if (slider.vars.pausePlay) { methods.pausePlay.update("pause"); }
831
      // SYNC:
832
      if (slider.syncExists) { methods.sync("play"); }
833
    };
834
    // STOP:
835
    slider.stop = function () {
836
      slider.pause();
837
      slider.stopped = true;
838
    };
839
    slider.canAdvance = function(target, fromNav) {
840
      // ASNAV:
841
      var last = (asNav) ? slider.pagingCount - 1 : slider.last;
842
      return (fromNav) ? true :
843
             (asNav && slider.currentItem === slider.count - 1 && target === 0 && slider.direction === "prev") ? true :
844
             (asNav && slider.currentItem === 0 && target === slider.pagingCount - 1 && slider.direction !== "next") ? false :
845
             (target === slider.currentSlide && !asNav) ? false :
846
             (slider.vars.animationLoop) ? true :
847
             (slider.atEnd && slider.currentSlide === 0 && target === last && slider.direction !== "next") ? false :
848
             (slider.atEnd && slider.currentSlide === last && target === 0 && slider.direction === "next") ? false :
849
             true;
850
    };
851
    slider.getTarget = function(dir) {
852
      slider.direction = dir;
853
      if (dir === "next") {
854
        return (slider.currentSlide === slider.last) ? 0 : slider.currentSlide + 1;
855
      } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
856
        return (slider.currentSlide === 0) ? slider.last : slider.currentSlide - 1;
857
      }
858
    };
859
860
    // SLIDE:
861 View Code Duplication
    slider.setProps = function(pos, special, dur) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
862
      var target = (function() {
863
        var posCheck = (pos) ? pos : ((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo,
864
            posCalc = (function() {
865
              if (carousel) {
866
                return (special === "setTouch") ? pos :
867
                       (reverse && slider.animatingTo === slider.last) ? 0 :
868
                       (reverse) ? slider.limit - (((slider.itemW + slider.vars.itemMargin) * slider.move) * slider.animatingTo) :
869
                       (slider.animatingTo === slider.last) ? slider.limit : posCheck;
870
              } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
871
                switch (special) {
872
                  case "setTotal": return (reverse) ? ((slider.count - 1) - slider.currentSlide + slider.cloneOffset) * pos : (slider.currentSlide + slider.cloneOffset) * pos;
873
                  case "setTouch": return (reverse) ? pos : pos;
874
                  case "jumpEnd": return (reverse) ? pos : slider.count * pos;
875
                  case "jumpStart": return (reverse) ? slider.count * pos : pos;
876
                  default: return pos;
877
                }
878
              }
879
            }());
880
881
            return (posCalc * -1) + "px";
882
          }());
883
884
      if (slider.transitions) {
885
        target = (vertical) ? "translate3d(0," + target + ",0)" : "translate3d(" + target + ",0,0)";
886
        dur = (dur !== undefined) ? (dur/1000) + "s" : "0s";
887
        slider.container.css("-" + slider.pfx + "-transition-duration", dur);
888
         slider.container.css("transition-duration", dur);
889
      }
890
891
      slider.args[slider.prop] = target;
892
      if (slider.transitions || dur === undefined) { slider.container.css(slider.args); }
893
894
      slider.container.css('transform',target);
895
    };
896
897
    slider.setup = function(type) {
898
      // SLIDE:
899
      if (!fade) {
900
        var sliderOffset, arr;
901
902
        if (type === "init") {
903
          slider.viewport = $('<div class="' + namespace + 'viewport"></div>').css({"overflow": "hidden", "position": "relative"}).appendTo(slider).append(slider.container);
904
          // INFINITE LOOP:
905
          slider.cloneCount = 0;
906
          slider.cloneOffset = 0;
907
          // REVERSE:
908
          if (reverse) {
909
            arr = $.makeArray(slider.slides).reverse();
910
            slider.slides = $(arr);
911
            slider.container.empty().append(slider.slides);
912
          }
913
        }
914
        // INFINITE LOOP && !CAROUSEL:
915
        if (slider.vars.animationLoop && !carousel) {
916
          slider.cloneCount = 2;
917
          slider.cloneOffset = 1;
918
          // clear out old clones
919
          if (type !== "init") { slider.container.find('.clone').remove(); }
920
          slider.container.append(methods.uniqueID(slider.slides.first().clone().addClass('clone')).attr('aria-hidden', 'true'))
921
                          .prepend(methods.uniqueID(slider.slides.last().clone().addClass('clone')).attr('aria-hidden', 'true'));
922
        }
923
        slider.newSlides = $(slider.vars.selector, slider);
924
925
        sliderOffset = (reverse) ? slider.count - 1 - slider.currentSlide + slider.cloneOffset : slider.currentSlide + slider.cloneOffset;
926
        // VERTICAL:
927
        if (vertical && !carousel) {
928
          slider.container.height((slider.count + slider.cloneCount) * 200 + "%").css("position", "absolute").width("100%");
929
          setTimeout(function(){
930
            slider.newSlides.css({"display": "block"});
931
            slider.doMath();
932
            slider.viewport.height(slider.h);
933
            slider.setProps(sliderOffset * slider.h, "init");
934
          }, (type === "init") ? 100 : 0);
935
        } else {
936
          slider.container.width((slider.count + slider.cloneCount) * 200 + "%");
937
          slider.setProps(sliderOffset * slider.computedW, "init");
938
          setTimeout(function(){
939
            slider.doMath();
940
            slider.newSlides.css({"width": slider.computedW, "marginRight" : slider.computedM, "float": "left", "display": "block"});
941
            // SMOOTH HEIGHT:
942
            if (slider.vars.smoothHeight) { methods.smoothHeight(); }
943
          }, (type === "init") ? 100 : 0);
944
        }
945
      } else { // FADE:
946
        slider.slides.css({"width": "100%", "float": "left", "marginRight": "-100%", "position": "relative"});
947
        if (type === "init") {
948
          if (!touch) {
949
            //slider.slides.eq(slider.currentSlide).fadeIn(slider.vars.animationSpeed, slider.vars.easing);
950
            if (slider.vars.fadeFirstSlide == false) {
951
              slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).css({"opacity": 1});
952
            } else {
953
              slider.slides.css({ "opacity": 0, "display": "block", "zIndex": 1 }).eq(slider.currentSlide).css({"zIndex": 2}).animate({"opacity": 1},slider.vars.animationSpeed,slider.vars.easing);
954
            }
955
          } else {
956
            slider.slides.css({ "opacity": 0, "display": "block", "webkitTransition": "opacity " + slider.vars.animationSpeed / 1000 + "s ease", "zIndex": 1 }).eq(slider.currentSlide).css({ "opacity": 1, "zIndex": 2});
957
          }
958
        }
959
        // SMOOTH HEIGHT:
960
        if (slider.vars.smoothHeight) { methods.smoothHeight(); }
961
      }
962
      // !CAROUSEL:
963
      // CANDIDATE: active slide
964
      if (!carousel) { slider.slides.removeClass(namespace + "active-slide").eq(slider.currentSlide).addClass(namespace + "active-slide"); }
965
966
      //FlexSlider: init() Callback
967
      slider.vars.init(slider);
968
    };
969
970
    slider.doMath = function() {
971
      var slide = slider.slides.first(),
972
          slideMargin = slider.vars.itemMargin,
973
          minItems = slider.vars.minItems,
974
          maxItems = slider.vars.maxItems;
975
976
      slider.w = (slider.viewport===undefined) ? slider.width() : slider.viewport.width();
977
      slider.h = slide.height();
978
      slider.boxPadding = slide.outerWidth() - slide.width();
979
980
      // CAROUSEL:
981
      if (carousel) {
982
        slider.itemT = slider.vars.itemWidth + slideMargin;
983
        slider.itemM = slideMargin;
984
        slider.minW = (minItems) ? minItems * slider.itemT : slider.w;
985
        slider.maxW = (maxItems) ? (maxItems * slider.itemT) - slideMargin : slider.w;
986
        slider.itemW = (slider.minW > slider.w) ? (slider.w - (slideMargin * (minItems - 1)))/minItems :
987
                       (slider.maxW < slider.w) ? (slider.w - (slideMargin * (maxItems - 1)))/maxItems :
988
                       (slider.vars.itemWidth > slider.w) ? slider.w : slider.vars.itemWidth;
989
990
        slider.visible = Math.floor(slider.w/(slider.itemW));
991
        slider.move = (slider.vars.move > 0 && slider.vars.move < slider.visible ) ? slider.vars.move : slider.visible;
992
        slider.pagingCount = Math.ceil(((slider.count - slider.visible)/slider.move) + 1);
993
        slider.last =  slider.pagingCount - 1;
994
        slider.limit = (slider.pagingCount === 1) ? 0 :
995
                       (slider.vars.itemWidth > slider.w) ? (slider.itemW * (slider.count - 1)) + (slideMargin * (slider.count - 1)) : ((slider.itemW + slideMargin) * slider.count) - slider.w - slideMargin;
996
      } else {
997
        slider.itemW = slider.w;
998
        slider.itemM = slideMargin;
999
        slider.pagingCount = slider.count;
1000
        slider.last = slider.count - 1;
1001
      }
1002
      slider.computedW = slider.itemW - slider.boxPadding;
1003
      slider.computedM = slider.itemM;
1004
    };
1005
1006
    slider.update = function(pos, action) {
1007
      slider.doMath();
1008
1009
      // update currentSlide and slider.animatingTo if necessary
1010
      if (!carousel) {
1011
        if (pos < slider.currentSlide) {
1012
          slider.currentSlide += 1;
1013
        } else if (pos <= slider.currentSlide && pos !== 0) {
1014
          slider.currentSlide -= 1;
1015
        }
1016
        slider.animatingTo = slider.currentSlide;
1017
      }
1018
1019
      // update controlNav
1020
      if (slider.vars.controlNav && !slider.manualControls) {
1021
        if ((action === "add" && !carousel) || slider.pagingCount > slider.controlNav.length) {
1022
          methods.controlNav.update("add");
1023
        } else if ((action === "remove" && !carousel) || slider.pagingCount < slider.controlNav.length) {
1024
          if (carousel && slider.currentSlide > slider.last) {
1025
            slider.currentSlide -= 1;
1026
            slider.animatingTo -= 1;
1027
          }
1028
          methods.controlNav.update("remove", slider.last);
1029
        }
1030
      }
1031
      // update directionNav
1032
      if (slider.vars.directionNav) { methods.directionNav.update(); }
1033
1034
    };
1035
1036
    slider.addSlide = function(obj, pos) {
1037
      var $obj = $(obj);
1038
1039
      slider.count += 1;
1040
      slider.last = slider.count - 1;
1041
1042
      // append new slide
1043
      if (vertical && reverse) {
1044
        (pos !== undefined) ? slider.slides.eq(slider.count - pos).after($obj) : slider.container.prepend($obj);
1045
      } else {
1046
        (pos !== undefined) ? slider.slides.eq(pos).before($obj) : slider.container.append($obj);
1047
      }
1048
1049
      // update currentSlide, animatingTo, controlNav, and directionNav
1050
      slider.update(pos, "add");
1051
1052
      // update slider.slides
1053
      slider.slides = $(slider.vars.selector + ':not(.clone)', slider);
1054
      // re-setup the slider to accomdate new slide
1055
      slider.setup();
1056
1057
      //FlexSlider: added() Callback
1058
      slider.vars.added(slider);
1059
    };
1060
    slider.removeSlide = function(obj) {
1061
      var pos = (isNaN(obj)) ? slider.slides.index($(obj)) : obj;
1062
1063
      // update count
1064
      slider.count -= 1;
1065
      slider.last = slider.count - 1;
1066
1067
      // remove slide
1068
      if (isNaN(obj)) {
1069
        $(obj, slider.slides).remove();
1070
      } else {
1071
        (vertical && reverse) ? slider.slides.eq(slider.last).remove() : slider.slides.eq(obj).remove();
1072
      }
1073
1074
      // update currentSlide, animatingTo, controlNav, and directionNav
1075
      slider.doMath();
1076
      slider.update(pos, "remove");
1077
1078
      // update slider.slides
1079
      slider.slides = $(slider.vars.selector + ':not(.clone)', slider);
1080
      // re-setup the slider to accomdate new slide
1081
      slider.setup();
1082
1083
      // FlexSlider: removed() Callback
1084
      slider.vars.removed(slider);
1085
    };
1086
1087
    //FlexSlider: Initialize
1088
    methods.init();
1089
  };
1090
1091
  // Ensure the slider isn't focussed if the window loses focus.
1092
  $( window ).blur( function ( e ) {
0 ignored issues
show
Unused Code introduced by
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1093
    focused = false;
1094
  }).focus( function ( e ) {
0 ignored issues
show
Unused Code introduced by
The parameter e is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1095
    focused = true;
1096
  });
1097
1098
  //FlexSlider: Default Settings
1099
  $.flexslider.defaults = {
1100
    namespace: "flex-",             //{NEW} String: Prefix string attached to the class of every element generated by the plugin
1101
    selector: ".slides > li",       //{NEW} Selector: Must match a simple pattern. '{container} > {slide}' -- Ignore pattern at your own peril
1102
    animation: "fade",              //String: Select your animation type, "fade" or "slide"
1103
    easing: "swing",                //{NEW} String: Determines the easing method used in jQuery transitions. jQuery easing plugin is supported!
1104
    direction: "horizontal",        //String: Select the sliding direction, "horizontal" or "vertical"
1105
    reverse: false,                 //{NEW} Boolean: Reverse the animation direction
1106
    animationLoop: true,            //Boolean: Should the animation loop? If false, directionNav will received "disable" classes at either end
1107
    smoothHeight: false,            //{NEW} Boolean: Allow height of the slider to animate smoothly in horizontal mode
1108
    startAt: 0,                     //Integer: The slide that the slider should start on. Array notation (0 = first slide)
1109
    slideshow: true,                //Boolean: Animate slider automatically
1110
    slideshowSpeed: 7000,           //Integer: Set the speed of the slideshow cycling, in milliseconds
1111
    animationSpeed: 600,            //Integer: Set the speed of animations, in milliseconds
1112
    initDelay: 0,                   //{NEW} Integer: Set an initialization delay, in milliseconds
1113
    randomize: false,               //Boolean: Randomize slide order
1114
    fadeFirstSlide: true,           //Boolean: Fade in the first slide when animation type is "fade"
1115
    thumbCaptions: false,           //Boolean: Whether or not to put captions on thumbnails when using the "thumbnails" controlNav.
1116
1117
    // Usability features
1118
    pauseOnAction: true,            //Boolean: Pause the slideshow when interacting with control elements, highly recommended.
1119
    pauseOnHover: false,            //Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering
1120
    pauseInvisible: true,   		//{NEW} Boolean: Pause the slideshow when tab is invisible, resume when visible. Provides better UX, lower CPU usage.
1121
    useCSS: true,                   //{NEW} Boolean: Slider will use CSS3 transitions if available
1122
    touch: true,                    //{NEW} Boolean: Allow touch swipe navigation of the slider on touch-enabled devices
1123
    video: false,                   //{NEW} Boolean: If using video in the slider, will prevent CSS3 3D Transforms to avoid graphical glitches
1124
1125
    // Primary Controls
1126
    controlNav: true,               //Boolean: Create navigation for paging control of each slide? Note: Leave true for manualControls usage
1127
    directionNav: true,             //Boolean: Create navigation for previous/next navigation? (true/false)
1128
    prevText: "Previous",           //String: Set the text for the "previous" directionNav item
1129
    nextText: "Next",               //String: Set the text for the "next" directionNav item
1130
1131
    // Secondary Navigation
1132
    keyboard: true,                 //Boolean: Allow slider navigating via keyboard left/right keys
1133
    multipleKeyboard: false,        //{NEW} Boolean: Allow keyboard navigation to affect multiple sliders. Default behavior cuts out keyboard navigation with more than one slider present.
1134
    mousewheel: false,              //{UPDATED} Boolean: Requires jquery.mousewheel.js (https://github.com/brandonaaron/jquery-mousewheel) - Allows slider navigating via mousewheel
1135
    pausePlay: false,               //Boolean: Create pause/play dynamic element
1136
    pauseText: "Pause",             //String: Set the text for the "pause" pausePlay item
1137
    playText: "Play",               //String: Set the text for the "play" pausePlay item
1138
1139
    // Special properties
1140
    controlsContainer: "",          //{UPDATED} jQuery Object/Selector: Declare which container the navigation elements should be appended too. Default container is the FlexSlider element. Example use would be $(".flexslider-container"). Property is ignored if given element is not found.
1141
    manualControls: "",             //{UPDATED} jQuery Object/Selector: Declare custom control navigation. Examples would be $(".flex-control-nav li") or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs.
1142
    customDirectionNav: "",         //{NEW} jQuery Object/Selector: Custom prev / next button. Must be two jQuery elements. In order to make the events work they have to have the classes "prev" and "next" (plus namespace)
1143
    sync: "",                       //{NEW} Selector: Mirror the actions performed on this slider with another slider. Use with care.
1144
    asNavFor: "",                   //{NEW} Selector: Internal property exposed for turning the slider into a thumbnail navigation for another slider
1145
1146
    // Carousel Options
1147
    itemWidth: 0,                   //{NEW} Integer: Box-model width of individual carousel items, including horizontal borders and padding.
1148
    itemMargin: 0,                  //{NEW} Integer: Margin between carousel items.
1149
    minItems: 1,                    //{NEW} Integer: Minimum number of carousel items that should be visible. Items will resize fluidly when below this.
1150
    maxItems: 0,                    //{NEW} Integer: Maxmimum number of carousel items that should be visible. Items will resize fluidly when above this limit.
1151
    move: 0,                        //{NEW} Integer: Number of carousel items that should move on animation. If 0, slider will move all visible items.
1152
    allowOneSlide: true,           //{NEW} Boolean: Whether or not to allow a slider comprised of a single slide
1153
1154
    // Callback API
1155
    start: function(){},            //Callback: function(slider) - Fires when the slider loads the first slide
1156
    before: function(){},           //Callback: function(slider) - Fires asynchronously with each slider animation
1157
    after: function(){},            //Callback: function(slider) - Fires after each slider animation completes
1158
    end: function(){},              //Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous)
1159
    added: function(){},            //{NEW} Callback: function(slider) - Fires after a slide is added
1160
    removed: function(){},           //{NEW} Callback: function(slider) - Fires after a slide is removed
1161
    init: function() {}             //{NEW} Callback: function(slider) - Fires after the slider is initially setup
1162
  };
1163
1164
  //FlexSlider: Plugin Function
1165
  $.fn.flexslider = function(options) {
1166
    if (options === undefined) { options = {}; }
1167
1168
    if (typeof options === "object") {
1169
      return this.each(function() {
1170
        var $this = $(this),
1171
            selector = (options.selector) ? options.selector : ".slides > li",
1172
            $slides = $this.find(selector);
1173
1174
      if ( ( $slides.length === 1 && options.allowOneSlide === false ) || $slides.length === 0 ) {
1175
          $slides.fadeIn(400);
1176
          if (options.start) { options.start($this); }
1177
        } else if ($this.data('flexslider') === undefined) {
1178
          new $.flexslider(this, options);
0 ignored issues
show
Unused Code Best Practice introduced by
The object created with new $.flexslider(this, options) is not used but discarded. Consider invoking another function instead of a constructor if you are doing this purely for side effects.
Loading history...
1179
        }
1180
      });
1181
    } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
1182
      // Helper strings to quickly perform functions on the slider
1183
      var $slider = $(this).data('flexslider');
1184
      switch (options) {
1185
        case "play": $slider.play(); break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1186
        case "pause": $slider.pause(); break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1187
        case "stop": $slider.stop(); break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1188
        case "next": $slider.flexAnimate($slider.getTarget("next"), true); break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1189
        case "prev":
1190
        case "previous": $slider.flexAnimate($slider.getTarget("prev"), true); break;
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
1191
        default: if (typeof options === "number") { $slider.flexAnimate(options, true); }
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
Complexity Best Practice introduced by
There is no return statement if typeof options === "number" is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
1192
      }
1193
    }
1194
  };
1195
})(jQuery);
1196