bxslider-rails 3.0.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1292 @@
1
+ /**
2
+ * BxSlider v4.1 - Fully loaded, responsive content slider
3
+ * http://bxslider.com
4
+ *
5
+ * Copyright 2012, Steven Wanderski - http://stevenwanderski.com - http://bxcreative.com
6
+ * Written while drinking Belgian ales and listening to jazz
7
+ *
8
+ * Released under the WTFPL license - http://sam.zoy.org/wtfpl/
9
+ */
10
+
11
+ ;(function($){
12
+
13
+ var plugin = {};
14
+
15
+ var defaults = {
16
+
17
+ // GENERAL
18
+ mode: 'horizontal',
19
+ slideSelector: '',
20
+ infiniteLoop: true,
21
+ hideControlOnEnd: false,
22
+ speed: 500,
23
+ easing: null,
24
+ slideMargin: 0,
25
+ startSlide: 0,
26
+ randomStart: false,
27
+ captions: false,
28
+ ticker: false,
29
+ tickerHover: false,
30
+ adaptiveHeight: false,
31
+ adaptiveHeightSpeed: 500,
32
+ video: false,
33
+ useCSS: true,
34
+ preloadImages: 'visible',
35
+
36
+ // TOUCH
37
+ touchEnabled: true,
38
+ swipeThreshold: 50,
39
+ oneToOneTouch: true,
40
+ preventDefaultSwipeX: true,
41
+ preventDefaultSwipeY: false,
42
+
43
+ // PAGER
44
+ pager: true,
45
+ pagerType: 'full',
46
+ pagerShortSeparator: ' / ',
47
+ pagerSelector: null,
48
+ buildPager: null,
49
+ pagerCustom: null,
50
+
51
+ // CONTROLS
52
+ controls: true,
53
+ nextText: 'Next',
54
+ prevText: 'Prev',
55
+ nextSelector: null,
56
+ prevSelector: null,
57
+ autoControls: false,
58
+ startText: 'Start',
59
+ stopText: 'Stop',
60
+ autoControlsCombine: false,
61
+ autoControlsSelector: null,
62
+
63
+ // AUTO
64
+ auto: false,
65
+ pause: 4000,
66
+ autoStart: true,
67
+ autoDirection: 'next',
68
+ autoHover: false,
69
+ autoDelay: 0,
70
+
71
+ // CAROUSEL
72
+ minSlides: 1,
73
+ maxSlides: 1,
74
+ moveSlides: 0,
75
+ slideWidth: 0,
76
+
77
+ // CALLBACKS
78
+ onSliderLoad: function() {},
79
+ onSlideBefore: function() {},
80
+ onSlideAfter: function() {},
81
+ onSlideNext: function() {},
82
+ onSlidePrev: function() {}
83
+ }
84
+
85
+ $.fn.bxSlider = function(options){
86
+
87
+ if(this.length == 0) return this;
88
+
89
+ // support mutltiple elements
90
+ if(this.length > 1){
91
+ this.each(function(){$(this).bxSlider(options)});
92
+ return this;
93
+ }
94
+
95
+ // create a namespace to be used throughout the plugin
96
+ var slider = {};
97
+ // set a reference to our slider element
98
+ var el = this;
99
+ plugin.el = this;
100
+
101
+ /**
102
+ * Makes slideshow responsive
103
+ */
104
+ // first get the original window dimens (thanks alot IE)
105
+ var windowWidth = $(window).width();
106
+ var windowHeight = $(window).height();
107
+
108
+
109
+
110
+ /**
111
+ * ===================================================================================
112
+ * = PRIVATE FUNCTIONS
113
+ * ===================================================================================
114
+ */
115
+
116
+ /**
117
+ * Initializes namespace settings to be used throughout plugin
118
+ */
119
+ var init = function(){
120
+ // merge user-supplied options with the defaults
121
+ slider.settings = $.extend({}, defaults, options);
122
+ // parse slideWidth setting
123
+ slider.settings.slideWidth = parseInt(slider.settings.slideWidth);
124
+ // store the original children
125
+ slider.children = el.children(slider.settings.slideSelector);
126
+ // check if actual number of slides is less than minSlides / maxSlides
127
+ if(slider.children.length < slider.settings.minSlides) slider.settings.minSlides = slider.children.length;
128
+ if(slider.children.length < slider.settings.maxSlides) slider.settings.maxSlides = slider.children.length;
129
+ // if random start, set the startSlide setting to random number
130
+ if(slider.settings.randomStart) slider.settings.startSlide = Math.floor(Math.random() * slider.children.length);
131
+ // store active slide information
132
+ slider.active = { index: slider.settings.startSlide }
133
+ // store if the slider is in carousel mode (displaying / moving multiple slides)
134
+ slider.carousel = slider.settings.minSlides > 1 || slider.settings.maxSlides > 1;
135
+ // if carousel, force preloadImages = 'all'
136
+ if(slider.carousel) slider.settings.preloadImages = 'all';
137
+ // calculate the min / max width thresholds based on min / max number of slides
138
+ // used to setup and update carousel slides dimensions
139
+ slider.minThreshold = (slider.settings.minSlides * slider.settings.slideWidth) + ((slider.settings.minSlides - 1) * slider.settings.slideMargin);
140
+ slider.maxThreshold = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin);
141
+ // store the current state of the slider (if currently animating, working is true)
142
+ slider.working = false;
143
+ // initialize the controls object
144
+ slider.controls = {};
145
+ // initialize an auto interval
146
+ slider.interval = null;
147
+ // determine which property to use for transitions
148
+ slider.animProp = slider.settings.mode == 'vertical' ? 'top' : 'left';
149
+ // determine if hardware acceleration can be used
150
+ slider.usingCSS = slider.settings.useCSS && slider.settings.mode != 'fade' && (function(){
151
+ // create our test div element
152
+ var div = document.createElement('div');
153
+ // css transition properties
154
+ var props = ['WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective'];
155
+ // test for each property
156
+ for(var i in props){
157
+ if(div.style[props[i]] !== undefined){
158
+ slider.cssPrefix = props[i].replace('Perspective', '').toLowerCase();
159
+ slider.animProp = '-' + slider.cssPrefix + '-transform';
160
+ return true;
161
+ }
162
+ }
163
+ return false;
164
+ }());
165
+ // if vertical mode always make maxSlides and minSlides equal
166
+ if(slider.settings.mode == 'vertical') slider.settings.maxSlides = slider.settings.minSlides;
167
+ // perform all DOM / CSS modifications
168
+ setup();
169
+ }
170
+
171
+ /**
172
+ * Performs all DOM and CSS modifications
173
+ */
174
+ var setup = function(){
175
+ // wrap el in a wrapper
176
+ el.wrap('<div class="bx-wrapper"><div class="bx-viewport"></div></div>');
177
+ // store a namspace reference to .bx-viewport
178
+ slider.viewport = el.parent();
179
+ // add a loading div to display while images are loading
180
+ slider.loader = $('<div class="bx-loading" />');
181
+ slider.viewport.prepend(slider.loader);
182
+ // set el to a massive width, to hold any needed slides
183
+ // also strip any margin and padding from el
184
+ el.css({
185
+ width: slider.settings.mode == 'horizontal' ? slider.children.length * 215 + '%' : 'auto',
186
+ position: 'relative'
187
+ });
188
+ // if using CSS, add the easing property
189
+ if(slider.usingCSS && slider.settings.easing){
190
+ el.css('-' + slider.cssPrefix + '-transition-timing-function', slider.settings.easing);
191
+ // if not using CSS and no easing value was supplied, use the default JS animation easing (swing)
192
+ }else if(!slider.settings.easing){
193
+ slider.settings.easing = 'swing';
194
+ }
195
+ var slidesShowing = getNumberSlidesShowing();
196
+ // make modifications to the viewport (.bx-viewport)
197
+ slider.viewport.css({
198
+ width: '100%',
199
+ overflow: 'hidden',
200
+ position: 'relative'
201
+ });
202
+ slider.viewport.parent().css({
203
+ maxWidth: getViewportMaxWidth()
204
+ });
205
+ // apply css to all slider children
206
+ slider.children.css({
207
+ 'float': slider.settings.mode == 'horizontal' ? 'left' : 'none',
208
+ listStyle: 'none',
209
+ position: 'relative'
210
+ });
211
+ // apply the calculated width after the float is applied to prevent scrollbar interference
212
+ slider.children.width(getSlideWidth());
213
+ // if slideMargin is supplied, add the css
214
+ if(slider.settings.mode == 'horizontal' && slider.settings.slideMargin > 0) slider.children.css('marginRight', slider.settings.slideMargin);
215
+ if(slider.settings.mode == 'vertical' && slider.settings.slideMargin > 0) slider.children.css('marginBottom', slider.settings.slideMargin);
216
+ // if "fade" mode, add positioning and z-index CSS
217
+ if(slider.settings.mode == 'fade'){
218
+ slider.children.css({
219
+ position: 'absolute',
220
+ zIndex: 0,
221
+ display: 'none'
222
+ });
223
+ // prepare the z-index on the showing element
224
+ slider.children.eq(slider.settings.startSlide).css({zIndex: 50, display: 'block'});
225
+ }
226
+ // create an element to contain all slider controls (pager, start / stop, etc)
227
+ slider.controls.el = $('<div class="bx-controls" />');
228
+ // if captions are requested, add them
229
+ if(slider.settings.captions) appendCaptions();
230
+ // if infinite loop, prepare additional slides
231
+ if(slider.settings.infiniteLoop && slider.settings.mode != 'fade' && !slider.settings.ticker){
232
+ var slice = slider.settings.mode == 'vertical' ? slider.settings.minSlides : slider.settings.maxSlides;
233
+ var sliceAppend = slider.children.slice(0, slice).clone().addClass('bx-clone');
234
+ var slicePrepend = slider.children.slice(-slice).clone().addClass('bx-clone');
235
+ el.append(sliceAppend).prepend(slicePrepend);
236
+ }
237
+ // check if startSlide is last slide
238
+ slider.active.last = slider.settings.startSlide == getPagerQty() - 1;
239
+ // if video is true, set up the fitVids plugin
240
+ if(slider.settings.video) el.fitVids();
241
+ // set the default preload selector (visible)
242
+ var preloadSelector = slider.children.eq(slider.settings.startSlide);
243
+ if (slider.settings.preloadImages == "all") preloadSelector = el.children();
244
+ // only check for control addition if not in "ticker" mode
245
+ if(!slider.settings.ticker){
246
+ // if pager is requested, add it
247
+ if(slider.settings.pager) appendPager();
248
+ // if controls are requested, add them
249
+ if(slider.settings.controls) appendControls();
250
+ // if auto is true, and auto controls are requested, add them
251
+ if(slider.settings.auto && slider.settings.autoControls) appendControlsAuto();
252
+ // if any control option is requested, add the controls wrapper
253
+ if(slider.settings.controls || slider.settings.autoControls || slider.settings.pager) slider.viewport.after(slider.controls.el);
254
+ // if ticker mode, do not allow a pager
255
+ }else{
256
+ slider.settings.pager = false;
257
+ }
258
+ // preload all images, then perform final DOM / CSS modifications that depend on images being loaded
259
+ preloadSelector.imagesLoaded(start);
260
+ }
261
+
262
+ /**
263
+ * Start the slider
264
+ */
265
+ var start = function(){
266
+ // remove the loading DOM element
267
+ slider.loader.remove();
268
+ // set the left / top position of "el"
269
+ setSlidePosition();
270
+ // if "vertical" mode, always use adaptiveHeight to prevent odd behavior
271
+ if (slider.settings.mode == 'vertical') slider.settings.adaptiveHeight = true;
272
+ // set the viewport height
273
+ slider.viewport.height(getViewportHeight());
274
+ // make sure everything is positioned just right (same as a window resize)
275
+ el.redrawSlider();
276
+ // onSliderLoad callback
277
+ slider.settings.onSliderLoad(slider.active.index);
278
+ // slider has been fully initialized
279
+ slider.initialized = true;
280
+ // bind the resize call to the window
281
+ $(window).bind('resize', resizeWindow);
282
+ // if auto is true, start the show
283
+ if (slider.settings.auto && slider.settings.autoStart) initAuto();
284
+ // if ticker is true, start the ticker
285
+ if (slider.settings.ticker) initTicker();
286
+ // if pager is requested, make the appropriate pager link active
287
+ if (slider.settings.pager) updatePagerActive(slider.settings.startSlide);
288
+ // check for any updates to the controls (like hideControlOnEnd updates)
289
+ if (slider.settings.controls) updateDirectionControls();
290
+ // if touchEnabled is true, setup the touch events
291
+ if (slider.settings.touchEnabled && !slider.settings.ticker) initTouch();
292
+ }
293
+
294
+ /**
295
+ * Returns the calculated height of the viewport, used to determine either adaptiveHeight or the maxHeight value
296
+ */
297
+ var getViewportHeight = function(){
298
+ var height = 0;
299
+ // first determine which children (slides) should be used in our height calculation
300
+ var children = $();
301
+ // if mode is not "vertical" and adaptiveHeight is false, include all children
302
+ if(slider.settings.mode != 'vertical' && !slider.settings.adaptiveHeight){
303
+ children = slider.children;
304
+ }else{
305
+ // if not carousel, return the single active child
306
+ if(!slider.carousel){
307
+ children = slider.children.eq(slider.active.index);
308
+ // if carousel, return a slice of children
309
+ }else{
310
+ // get the individual slide index
311
+ var currentIndex = slider.settings.moveSlides == 1 ? slider.active.index : slider.active.index * getMoveBy();
312
+ // add the current slide to the children
313
+ children = slider.children.eq(currentIndex);
314
+ // cycle through the remaining "showing" slides
315
+ for (i = 1; i <= slider.settings.maxSlides - 1; i++){
316
+ // if looped back to the start
317
+ if(currentIndex + i >= slider.children.length){
318
+ children = children.add(slider.children.eq(i - 1));
319
+ }else{
320
+ children = children.add(slider.children.eq(currentIndex + i));
321
+ }
322
+ }
323
+ }
324
+ }
325
+ // if "vertical" mode, calculate the sum of the heights of the children
326
+ if(slider.settings.mode == 'vertical'){
327
+ children.each(function(index) {
328
+ height += $(this).outerHeight();
329
+ });
330
+ // add user-supplied margins
331
+ if(slider.settings.slideMargin > 0){
332
+ height += slider.settings.slideMargin * (slider.settings.minSlides - 1);
333
+ }
334
+ // if not "vertical" mode, calculate the max height of the children
335
+ }else{
336
+ height = Math.max.apply(Math, children.map(function(){
337
+ return $(this).outerHeight(false);
338
+ }).get());
339
+ }
340
+ return height;
341
+ }
342
+
343
+ /**
344
+ * Returns the calculated width to be used for the outer wrapper / viewport
345
+ */
346
+ var getViewportMaxWidth = function(){
347
+ var width = '100%';
348
+ if(slider.settings.slideWidth > 0){
349
+ if(slider.settings.mode == 'horizontal'){
350
+ width = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin);
351
+ }else{
352
+ width = slider.settings.slideWidth;
353
+ }
354
+ }
355
+ return width;
356
+ }
357
+
358
+ /**
359
+ * Returns the calculated width to be applied to each slide
360
+ */
361
+ var getSlideWidth = function(){
362
+ // start with any user-supplied slide width
363
+ var newElWidth = slider.settings.slideWidth;
364
+ // get the current viewport width
365
+ var wrapWidth = slider.viewport.width();
366
+ // if slide width was not supplied, or is larger than the viewport use the viewport width
367
+ if(slider.settings.slideWidth == 0 ||
368
+ (slider.settings.slideWidth > wrapWidth && !slider.carousel) ||
369
+ slider.settings.mode == 'vertical'){
370
+ newElWidth = wrapWidth;
371
+ // if carousel, use the thresholds to determine the width
372
+ }else if(slider.settings.maxSlides > 1 && slider.settings.mode == 'horizontal'){
373
+ if(wrapWidth > slider.maxThreshold){
374
+ // newElWidth = (wrapWidth - (slider.settings.slideMargin * (slider.settings.maxSlides - 1))) / slider.settings.maxSlides;
375
+ }else if(wrapWidth < slider.minThreshold){
376
+ newElWidth = (wrapWidth - (slider.settings.slideMargin * (slider.settings.minSlides - 1))) / slider.settings.minSlides;
377
+ }
378
+ }
379
+ return newElWidth;
380
+ }
381
+
382
+ /**
383
+ * Returns the number of slides currently visible in the viewport (includes partially visible slides)
384
+ */
385
+ var getNumberSlidesShowing = function(){
386
+ var slidesShowing = 1;
387
+ if(slider.settings.mode == 'horizontal' && slider.settings.slideWidth > 0){
388
+ // if viewport is smaller than minThreshold, return minSlides
389
+ if(slider.viewport.width() < slider.minThreshold){
390
+ slidesShowing = slider.settings.minSlides;
391
+ // if viewport is larger than minThreshold, return maxSlides
392
+ }else if(slider.viewport.width() > slider.maxThreshold){
393
+ slidesShowing = slider.settings.maxSlides;
394
+ // if viewport is between min / max thresholds, divide viewport width by first child width
395
+ }else{
396
+ var childWidth = slider.children.first().width();
397
+ slidesShowing = Math.floor(slider.viewport.width() / childWidth);
398
+ }
399
+ // if "vertical" mode, slides showing will always be minSlides
400
+ }else if(slider.settings.mode == 'vertical'){
401
+ slidesShowing = slider.settings.minSlides;
402
+ }
403
+ return slidesShowing;
404
+ }
405
+
406
+ /**
407
+ * Returns the number of pages (one full viewport of slides is one "page")
408
+ */
409
+ var getPagerQty = function(){
410
+ var pagerQty = 0;
411
+ // if moveSlides is specified by the user
412
+ if(slider.settings.moveSlides > 0){
413
+ if(slider.settings.infiniteLoop){
414
+ pagerQty = slider.children.length / getMoveBy();
415
+ }else{
416
+ // use a while loop to determine pages
417
+ var breakPoint = 0;
418
+ var counter = 0
419
+ // when breakpoint goes above children length, counter is the number of pages
420
+ while (breakPoint < slider.children.length){
421
+ ++pagerQty;
422
+ breakPoint = counter + getNumberSlidesShowing();
423
+ counter += slider.settings.moveSlides <= getNumberSlidesShowing() ? slider.settings.moveSlides : getNumberSlidesShowing();
424
+ }
425
+ }
426
+ // if moveSlides is 0 (auto) divide children length by sides showing, then round up
427
+ }else{
428
+ pagerQty = Math.ceil(slider.children.length / getNumberSlidesShowing());
429
+ }
430
+ return pagerQty;
431
+ }
432
+
433
+ /**
434
+ * Returns the number of indivual slides by which to shift the slider
435
+ */
436
+ var getMoveBy = function(){
437
+ // if moveSlides was set by the user and moveSlides is less than number of slides showing
438
+ if(slider.settings.moveSlides > 0 && slider.settings.moveSlides <= getNumberSlidesShowing()){
439
+ return slider.settings.moveSlides;
440
+ }
441
+ // if moveSlides is 0 (auto)
442
+ return getNumberSlidesShowing();
443
+ }
444
+
445
+ /**
446
+ * Sets the slider's (el) left or top position
447
+ */
448
+ var setSlidePosition = function(){
449
+ // if last slide, not infinite loop, and number of children is larger than specified maxSlides
450
+ if(slider.children.length > slider.settings.maxSlides && slider.active.last && !slider.settings.infiniteLoop){
451
+ if (slider.settings.mode == 'horizontal'){
452
+ // get the last child's position
453
+ var lastChild = slider.children.last();
454
+ var position = lastChild.position();
455
+ // set the left position
456
+ setPositionProperty(-(position.left - (slider.viewport.width() - lastChild.width())), 'reset', 0);
457
+ }else if(slider.settings.mode == 'vertical'){
458
+ // get the last showing index's position
459
+ var lastShowingIndex = slider.children.length - slider.settings.minSlides;
460
+ var position = slider.children.eq(lastShowingIndex).position();
461
+ // set the top position
462
+ setPositionProperty(-position.top, 'reset', 0);
463
+ }
464
+ // if not last slide
465
+ }else{
466
+ // get the position of the first showing slide
467
+ var position = slider.children.eq(slider.active.index * getMoveBy()).position();
468
+ // check for last slide
469
+ if (slider.active.index == getPagerQty() - 1) slider.active.last = true;
470
+ // set the repective position
471
+ if (position != undefined){
472
+ if (slider.settings.mode == 'horizontal') setPositionProperty(-position.left, 'reset', 0);
473
+ else if (slider.settings.mode == 'vertical') setPositionProperty(-position.top, 'reset', 0);
474
+ }
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Sets the el's animating property position (which in turn will sometimes animate el).
480
+ * If using CSS, sets the transform property. If not using CSS, sets the top / left property.
481
+ *
482
+ * @param value (int)
483
+ * - the animating property's value
484
+ *
485
+ * @param type (string) 'slider', 'reset', 'ticker'
486
+ * - the type of instance for which the function is being
487
+ *
488
+ * @param duration (int)
489
+ * - the amount of time (in ms) the transition should occupy
490
+ *
491
+ * @param params (array) optional
492
+ * - an optional parameter containing any variables that need to be passed in
493
+ */
494
+ var setPositionProperty = function(value, type, duration, params){
495
+ // use CSS transform
496
+ if(slider.usingCSS){
497
+ // determine the translate3d value
498
+ var propValue = slider.settings.mode == 'vertical' ? 'translate3d(0, ' + value + 'px, 0)' : 'translate3d(' + value + 'px, 0, 0)';
499
+ // add the CSS transition-duration
500
+ el.css('-' + slider.cssPrefix + '-transition-duration', duration / 1000 + 's');
501
+ if(type == 'slide'){
502
+ // set the property value
503
+ el.css(slider.animProp, propValue);
504
+ // bind a callback method - executes when CSS transition completes
505
+ el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(){
506
+ // unbind the callback
507
+ el.unbind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd');
508
+ updateAfterSlideTransition();
509
+ });
510
+ }else if(type == 'reset'){
511
+ el.css(slider.animProp, propValue);
512
+ }else if(type == 'ticker'){
513
+ // make the transition use 'linear'
514
+ el.css('-' + slider.cssPrefix + '-transition-timing-function', 'linear');
515
+ el.css(slider.animProp, propValue);
516
+ // bind a callback method - executes when CSS transition completes
517
+ el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(){
518
+ // unbind the callback
519
+ el.unbind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd');
520
+ // reset the position
521
+ setPositionProperty(params['resetValue'], 'reset', 0);
522
+ // start the loop again
523
+ tickerLoop();
524
+ });
525
+ }
526
+ // use JS animate
527
+ }else{
528
+ var animateObj = {};
529
+ animateObj[slider.animProp] = value;
530
+ if(type == 'slide'){
531
+ el.animate(animateObj, duration, slider.settings.easing, function(){
532
+ updateAfterSlideTransition();
533
+ });
534
+ }else if(type == 'reset'){
535
+ el.css(slider.animProp, value)
536
+ }else if(type == 'ticker'){
537
+ el.animate(animateObj, speed, 'linear', function(){
538
+ setPositionProperty(params['resetValue'], 'reset', 0);
539
+ // run the recursive loop after animation
540
+ tickerLoop();
541
+ });
542
+ }
543
+ }
544
+ }
545
+
546
+ /**
547
+ * Populates the pager with proper amount of pages
548
+ */
549
+ var populatePager = function(){
550
+ var pagerHtml = '';
551
+ var pagerQty = getPagerQty();
552
+ // loop through each pager item
553
+ for(var i=0; i < pagerQty; i++){
554
+ var linkContent = '';
555
+ // if a buildPager function is supplied, use it to get pager link value, else use index + 1
556
+ if(slider.settings.buildPager && $.isFunction(slider.settings.buildPager)){
557
+ linkContent = slider.settings.buildPager(i);
558
+ slider.pagerEl.addClass('bx-custom-pager');
559
+ }else{
560
+ linkContent = i + 1;
561
+ slider.pagerEl.addClass('bx-default-pager');
562
+ }
563
+ // var linkContent = slider.settings.buildPager && $.isFunction(slider.settings.buildPager) ? slider.settings.buildPager(i) : i + 1;
564
+ // add the markup to the string
565
+ pagerHtml += '<div class="bx-pager-item"><a href="" data-slide-index="' + i + '" class="bx-pager-link">' + linkContent + '</a></div>';
566
+ };
567
+ // populate the pager element with pager links
568
+ slider.pagerEl.html(pagerHtml);
569
+ }
570
+
571
+ /**
572
+ * Appends the pager to the controls element
573
+ */
574
+ var appendPager = function(){
575
+ if(!slider.settings.pagerCustom){
576
+ // create the pager DOM element
577
+ slider.pagerEl = $('<div class="bx-pager" />');
578
+ // if a pager selector was supplied, populate it with the pager
579
+ if(slider.settings.pagerSelector){
580
+ $(slider.settings.pagerSelector).html(slider.pagerEl);
581
+ // if no pager selector was supplied, add it after the wrapper
582
+ }else{
583
+ slider.controls.el.addClass('bx-has-pager').append(slider.pagerEl);
584
+ }
585
+ // populate the pager
586
+ populatePager();
587
+ }else{
588
+ slider.pagerEl = $(slider.settings.pagerCustom);
589
+ }
590
+ // assign the pager click binding
591
+ slider.pagerEl.delegate('a', 'click', clickPagerBind);
592
+ }
593
+
594
+ /**
595
+ * Appends prev / next controls to the controls element
596
+ */
597
+ var appendControls = function(){
598
+ slider.controls.next = $('<a class="bx-next" href="">' + slider.settings.nextText + '</a>');
599
+ slider.controls.prev = $('<a class="bx-prev" href="">' + slider.settings.prevText + '</a>');
600
+ // bind click actions to the controls
601
+ slider.controls.next.bind('click', clickNextBind);
602
+ slider.controls.prev.bind('click', clickPrevBind);
603
+ // if nextSlector was supplied, populate it
604
+ if(slider.settings.nextSelector){
605
+ $(slider.settings.nextSelector).append(slider.controls.next);
606
+ }
607
+ // if prevSlector was supplied, populate it
608
+ if(slider.settings.prevSelector){
609
+ $(slider.settings.prevSelector).append(slider.controls.prev);
610
+ }
611
+ // if no custom selectors were supplied
612
+ if(!slider.settings.nextSelector && !slider.settings.prevSelector){
613
+ // add the controls to the DOM
614
+ slider.controls.directionEl = $('<div class="bx-controls-direction" />');
615
+ // add the control elements to the directionEl
616
+ slider.controls.directionEl.append(slider.controls.prev).append(slider.controls.next);
617
+ // slider.viewport.append(slider.controls.directionEl);
618
+ slider.controls.el.addClass('bx-has-controls-direction').append(slider.controls.directionEl);
619
+ }
620
+ }
621
+
622
+ /**
623
+ * Appends start / stop auto controls to the controls element
624
+ */
625
+ var appendControlsAuto = function(){
626
+ slider.controls.start = $('<div class="bx-controls-auto-item"><a class="bx-start" href="">' + slider.settings.startText + '</a></div>');
627
+ slider.controls.stop = $('<div class="bx-controls-auto-item"><a class="bx-stop" href="">' + slider.settings.stopText + '</a></div>');
628
+ // add the controls to the DOM
629
+ slider.controls.autoEl = $('<div class="bx-controls-auto" />');
630
+ // bind click actions to the controls
631
+ slider.controls.autoEl.delegate('.bx-start', 'click', clickStartBind);
632
+ slider.controls.autoEl.delegate('.bx-stop', 'click', clickStopBind);
633
+ // if autoControlsCombine, insert only the "start" control
634
+ if(slider.settings.autoControlsCombine){
635
+ slider.controls.autoEl.append(slider.controls.start);
636
+ // if autoControlsCombine is false, insert both controls
637
+ }else{
638
+ slider.controls.autoEl.append(slider.controls.start).append(slider.controls.stop);
639
+ }
640
+ // if auto controls selector was supplied, populate it with the controls
641
+ if(slider.settings.autoControlsSelector){
642
+ $(slider.settings.autoControlsSelector).html(slider.controls.autoEl);
643
+ // if auto controls selector was not supplied, add it after the wrapper
644
+ }else{
645
+ slider.controls.el.addClass('bx-has-controls-auto').append(slider.controls.autoEl);
646
+ }
647
+ // update the auto controls
648
+ updateAutoControls(slider.settings.autoStart ? 'stop' : 'start');
649
+ }
650
+
651
+ /**
652
+ * Appends image captions to the DOM
653
+ */
654
+ var appendCaptions = function(){
655
+ // cycle through each child
656
+ slider.children.each(function(index){
657
+ // get the image title attribute
658
+ var title = $(this).find('img:first').attr('title');
659
+ // append the caption
660
+ if (title != undefined) $(this).append('<div class="bx-caption"><span>' + title + '</span></div>');
661
+ });
662
+ }
663
+
664
+ /**
665
+ * Click next binding
666
+ *
667
+ * @param e (event)
668
+ * - DOM event object
669
+ */
670
+ var clickNextBind = function(e){
671
+ // if auto show is running, stop it
672
+ if (slider.settings.auto) el.stopAuto();
673
+ el.goToNextSlide();
674
+ e.preventDefault();
675
+ }
676
+
677
+ /**
678
+ * Click prev binding
679
+ *
680
+ * @param e (event)
681
+ * - DOM event object
682
+ */
683
+ var clickPrevBind = function(e){
684
+ // if auto show is running, stop it
685
+ if (slider.settings.auto) el.stopAuto();
686
+ el.goToPrevSlide();
687
+ e.preventDefault();
688
+ }
689
+
690
+ /**
691
+ * Click start binding
692
+ *
693
+ * @param e (event)
694
+ * - DOM event object
695
+ */
696
+ var clickStartBind = function(e){
697
+ el.startAuto();
698
+ e.preventDefault();
699
+ }
700
+
701
+ /**
702
+ * Click stop binding
703
+ *
704
+ * @param e (event)
705
+ * - DOM event object
706
+ */
707
+ var clickStopBind = function(e){
708
+ el.stopAuto();
709
+ e.preventDefault();
710
+ }
711
+
712
+ /**
713
+ * Click pager binding
714
+ *
715
+ * @param e (event)
716
+ * - DOM event object
717
+ */
718
+ var clickPagerBind = function(e){
719
+ // if auto show is running, stop it
720
+ if (slider.settings.auto) el.stopAuto();
721
+ var pagerLink = $(e.currentTarget);
722
+ var pagerIndex = parseInt(pagerLink.attr('data-slide-index'));
723
+ // if clicked pager link is not active, continue with the goToSlide call
724
+ if(pagerIndex != slider.active.index) el.goToSlide(pagerIndex);
725
+ e.preventDefault();
726
+ }
727
+
728
+ /**
729
+ * Updates the pager links with an active class
730
+ *
731
+ * @param slideIndex (int)
732
+ * - index of slide to make active
733
+ */
734
+ var updatePagerActive = function(slideIndex){
735
+ // if "short" pager type
736
+ if(slider.settings.pagerType == 'short'){
737
+ slider.pagerEl.html((slideIndex + 1) + slider.settings.pagerShortSeparator + slider.children.length);
738
+ return;
739
+ }
740
+ // remove all pager active classes
741
+ slider.pagerEl.find('a').removeClass('active');
742
+ // apply the active class for all pagers
743
+ slider.pagerEl.each(function(i, el) { $(el).find('a').eq(slideIndex).addClass('active'); });
744
+ }
745
+
746
+ /**
747
+ * Performs needed actions after a slide transition
748
+ */
749
+ var updateAfterSlideTransition = function(){
750
+ // if infinte loop is true
751
+ if(slider.settings.infiniteLoop){
752
+ var position = '';
753
+ // first slide
754
+ if(slider.active.index == 0){
755
+ // set the new position
756
+ position = slider.children.eq(0).position();
757
+ // carousel, last slide
758
+ }else if(slider.active.index == getPagerQty() - 1 && slider.carousel){
759
+ position = slider.children.eq((getPagerQty() - 1) * getMoveBy()).position();
760
+ // last slide
761
+ }else if(slider.active.index == slider.children.length - 1){
762
+ position = slider.children.eq(slider.children.length - 1).position();
763
+ }
764
+ if (slider.settings.mode == 'horizontal') { setPositionProperty(-position.left, 'reset', 0);; }
765
+ else if (slider.settings.mode == 'vertical') { setPositionProperty(-position.top, 'reset', 0);; }
766
+ }
767
+ // declare that the transition is complete
768
+ slider.working = false;
769
+ // onSlideAfter callback
770
+ slider.settings.onSlideAfter(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index);
771
+ }
772
+
773
+ /**
774
+ * Updates the auto controls state (either active, or combined switch)
775
+ *
776
+ * @param state (string) "start", "stop"
777
+ * - the new state of the auto show
778
+ */
779
+ var updateAutoControls = function(state){
780
+ // if autoControlsCombine is true, replace the current control with the new state
781
+ if(slider.settings.autoControlsCombine){
782
+ slider.controls.autoEl.html(slider.controls[state]);
783
+ // if autoControlsCombine is false, apply the "active" class to the appropriate control
784
+ }else{
785
+ slider.controls.autoEl.find('a').removeClass('active');
786
+ slider.controls.autoEl.find('a:not(.bx-' + state + ')').addClass('active');
787
+ }
788
+ }
789
+
790
+ /**
791
+ * Updates the direction controls (checks if either should be hidden)
792
+ */
793
+ var updateDirectionControls = function(){
794
+ if(getPagerQty() == 1){
795
+ slider.controls.prev.addClass('disabled');
796
+ slider.controls.next.addClass('disabled');
797
+ }else if(!slider.settings.infiniteLoop && slider.settings.hideControlOnEnd){
798
+ // if first slide
799
+ if (slider.active.index == 0){
800
+ slider.controls.prev.addClass('disabled');
801
+ slider.controls.next.removeClass('disabled');
802
+ // if last slide
803
+ }else if(slider.active.index == getPagerQty() - 1){
804
+ slider.controls.next.addClass('disabled');
805
+ slider.controls.prev.removeClass('disabled');
806
+ // if any slide in the middle
807
+ }else{
808
+ slider.controls.prev.removeClass('disabled');
809
+ slider.controls.next.removeClass('disabled');
810
+ }
811
+ }
812
+ }
813
+
814
+ /**
815
+ * Initialzes the auto process
816
+ */
817
+ var initAuto = function(){
818
+ // if autoDelay was supplied, launch the auto show using a setTimeout() call
819
+ if(slider.settings.autoDelay > 0){
820
+ var timeout = setTimeout(el.startAuto, slider.settings.autoDelay);
821
+ // if autoDelay was not supplied, start the auto show normally
822
+ }else{
823
+ el.startAuto();
824
+ }
825
+ // if autoHover is requested
826
+ if(slider.settings.autoHover){
827
+ // on el hover
828
+ el.hover(function(){
829
+ // if the auto show is currently playing (has an active interval)
830
+ if(slider.interval){
831
+ // stop the auto show and pass true agument which will prevent control update
832
+ el.stopAuto(true);
833
+ // create a new autoPaused value which will be used by the relative "mouseout" event
834
+ slider.autoPaused = true;
835
+ }
836
+ }, function(){
837
+ // if the autoPaused value was created be the prior "mouseover" event
838
+ if(slider.autoPaused){
839
+ // start the auto show and pass true agument which will prevent control update
840
+ el.startAuto(true);
841
+ // reset the autoPaused value
842
+ slider.autoPaused = null;
843
+ }
844
+ });
845
+ }
846
+ }
847
+
848
+ /**
849
+ * Initialzes the ticker process
850
+ */
851
+ var initTicker = function(){
852
+ var startPosition = 0;
853
+ // if autoDirection is "next", append a clone of the entire slider
854
+ if(slider.settings.autoDirection == 'next'){
855
+ el.append(slider.children.clone().addClass('bx-clone'));
856
+ // if autoDirection is "prev", prepend a clone of the entire slider, and set the left position
857
+ }else{
858
+ el.prepend(slider.children.clone().addClass('bx-clone'));
859
+ var position = slider.children.first().position();
860
+ startPosition = slider.settings.mode == 'horizontal' ? -position.left : -position.top;
861
+ }
862
+ setPositionProperty(startPosition, 'reset', 0);
863
+ // do not allow controls in ticker mode
864
+ slider.settings.pager = false;
865
+ slider.settings.controls = false;
866
+ slider.settings.autoControls = false;
867
+ // if autoHover is requested
868
+ if(slider.settings.tickerHover && !slider.usingCSS){
869
+ // on el hover
870
+ slider.viewport.hover(function(){
871
+ el.stop();
872
+ }, function(){
873
+ // calculate the total width of children (used to calculate the speed ratio)
874
+ var totalDimens = 0;
875
+ slider.children.each(function(index){
876
+ totalDimens += slider.settings.mode == 'horizontal' ? $(this).outerWidth(true) : $(this).outerHeight(true);
877
+ });
878
+ // calculate the speed ratio (used to determine the new speed to finish the paused animation)
879
+ var ratio = slider.settings.speed / totalDimens;
880
+ // determine which property to use
881
+ var property = slider.settings.mode == 'horizontal' ? 'left' : 'top';
882
+ // calculate the new speed
883
+ var newSpeed = ratio * (totalDimens - (Math.abs(parseInt(el.css(property)))));
884
+ tickerLoop(newSpeed);
885
+ });
886
+ }
887
+ // start the ticker loop
888
+ tickerLoop();
889
+ }
890
+
891
+ /**
892
+ * Runs a continuous loop, news ticker-style
893
+ */
894
+ var tickerLoop = function(resumeSpeed){
895
+ speed = resumeSpeed ? resumeSpeed : slider.settings.speed;
896
+ var position = {left: 0, top: 0};
897
+ var reset = {left: 0, top: 0};
898
+ // if "next" animate left position to last child, then reset left to 0
899
+ if(slider.settings.autoDirection == 'next'){
900
+ position = el.find('.bx-clone').first().position();
901
+ // if "prev" animate left position to 0, then reset left to first non-clone child
902
+ }else{
903
+ reset = slider.children.first().position();
904
+ }
905
+ var animateProperty = slider.settings.mode == 'horizontal' ? -position.left : -position.top;
906
+ var resetValue = slider.settings.mode == 'horizontal' ? -reset.left : -reset.top;
907
+ var params = {resetValue: resetValue};
908
+ setPositionProperty(animateProperty, 'ticker', speed, params);
909
+ }
910
+
911
+ /**
912
+ * Initializes touch events
913
+ */
914
+ var initTouch = function(){
915
+ // initialize object to contain all touch values
916
+ slider.touch = {
917
+ start: {x: 0, y: 0},
918
+ end: {x: 0, y: 0}
919
+ }
920
+ slider.viewport.bind('touchstart', onTouchStart);
921
+ }
922
+
923
+ /**
924
+ * Event handler for "touchstart"
925
+ *
926
+ * @param e (event)
927
+ * - DOM event object
928
+ */
929
+ var onTouchStart = function(e){
930
+ if(slider.working){
931
+ e.preventDefault();
932
+ }else{
933
+ // record the original position when touch starts
934
+ slider.touch.originalPos = el.position();
935
+ var orig = e.originalEvent;
936
+ // record the starting touch x, y coordinates
937
+ slider.touch.start.x = orig.changedTouches[0].pageX;
938
+ slider.touch.start.y = orig.changedTouches[0].pageY;
939
+ // bind a "touchmove" event to the viewport
940
+ slider.viewport.bind('touchmove', onTouchMove);
941
+ // bind a "touchend" event to the viewport
942
+ slider.viewport.bind('touchend', onTouchEnd);
943
+ }
944
+ }
945
+
946
+ /**
947
+ * Event handler for "touchmove"
948
+ *
949
+ * @param e (event)
950
+ * - DOM event object
951
+ */
952
+ var onTouchMove = function(e){
953
+ var orig = e.originalEvent;
954
+ // if scrolling on y axis, do not prevent default
955
+ var xMovement = Math.abs(orig.changedTouches[0].pageX - slider.touch.start.x);
956
+ var yMovement = Math.abs(orig.changedTouches[0].pageY - slider.touch.start.y);
957
+ // x axis swipe
958
+ if((xMovement * 3) > yMovement && slider.settings.preventDefaultSwipeX){
959
+ e.preventDefault();
960
+ // y axis swipe
961
+ }else if((yMovement * 3) > xMovement && slider.settings.preventDefaultSwipeY){
962
+ e.preventDefault();
963
+ }
964
+ if(slider.settings.mode != 'fade' && slider.settings.oneToOneTouch){
965
+ var value = 0;
966
+ // if horizontal, drag along x axis
967
+ if(slider.settings.mode == 'horizontal'){
968
+ var change = orig.changedTouches[0].pageX - slider.touch.start.x;
969
+ value = slider.touch.originalPos.left + change;
970
+ // if vertical, drag along y axis
971
+ }else{
972
+ var change = orig.changedTouches[0].pageY - slider.touch.start.y;
973
+ value = slider.touch.originalPos.top + change;
974
+ }
975
+ setPositionProperty(value, 'reset', 0);
976
+ }
977
+ }
978
+
979
+ /**
980
+ * Event handler for "touchend"
981
+ *
982
+ * @param e (event)
983
+ * - DOM event object
984
+ */
985
+ var onTouchEnd = function(e){
986
+ slider.viewport.unbind('touchmove', onTouchMove);
987
+ var orig = e.originalEvent;
988
+ var value = 0;
989
+ // record end x, y positions
990
+ slider.touch.end.x = orig.changedTouches[0].pageX;
991
+ slider.touch.end.y = orig.changedTouches[0].pageY;
992
+ // if fade mode, check if absolute x distance clears the threshold
993
+ if(slider.settings.mode == 'fade'){
994
+ var distance = Math.abs(slider.touch.start.x - slider.touch.end.x);
995
+ if(distance >= slider.settings.swipeThreshold){
996
+ slider.touch.start.x > slider.touch.end.x ? el.goToNextSlide() : el.goToPrevSlide();
997
+ el.stopAuto();
998
+ }
999
+ // not fade mode
1000
+ }else{
1001
+ var distance = 0;
1002
+ // calculate distance and el's animate property
1003
+ if(slider.settings.mode == 'horizontal'){
1004
+ distance = slider.touch.end.x - slider.touch.start.x;
1005
+ value = slider.touch.originalPos.left;
1006
+ }else{
1007
+ distance = slider.touch.end.y - slider.touch.start.y;
1008
+ value = slider.touch.originalPos.top;
1009
+ }
1010
+ // if not infinite loop and first / last slide, do not attempt a slide transition
1011
+ if(!slider.settings.infiniteLoop && ((slider.active.index == 0 && distance > 0) || (slider.active.last && distance < 0))){
1012
+ setPositionProperty(value, 'reset', 200);
1013
+ }else{
1014
+ // check if distance clears threshold
1015
+ if(Math.abs(distance) >= slider.settings.swipeThreshold){
1016
+ distance < 0 ? el.goToNextSlide() : el.goToPrevSlide();
1017
+ el.stopAuto();
1018
+ }else{
1019
+ // el.animate(property, 200);
1020
+ setPositionProperty(value, 'reset', 200);
1021
+ }
1022
+ }
1023
+ }
1024
+ slider.viewport.unbind('touchend', onTouchEnd);
1025
+ }
1026
+
1027
+ /**
1028
+ * Window resize event callback
1029
+ */
1030
+ var resizeWindow = function(e){
1031
+ // get the new window dimens (again, thank you IE)
1032
+ var windowWidthNew = $(window).width();
1033
+ var windowHeightNew = $(window).height();
1034
+ // make sure that it is a true window resize
1035
+ // *we must check this because our dinosaur friend IE fires a window resize event when certain DOM elements
1036
+ // are resized. Can you just die already?*
1037
+ if(windowWidth != windowWidthNew || windowHeight != windowHeightNew){
1038
+ // set the new window dimens
1039
+ windowWidth = windowWidthNew;
1040
+ windowHeight = windowHeightNew;
1041
+ // update all dynamic elements
1042
+ el.redrawSlider();
1043
+ }
1044
+ }
1045
+
1046
+ /**
1047
+ * ===================================================================================
1048
+ * = PUBLIC FUNCTIONS
1049
+ * ===================================================================================
1050
+ */
1051
+
1052
+ /**
1053
+ * Performs slide transition to the specified slide
1054
+ *
1055
+ * @param slideIndex (int)
1056
+ * - the destination slide's index (zero-based)
1057
+ *
1058
+ * @param direction (string)
1059
+ * - INTERNAL USE ONLY - the direction of travel ("prev" / "next")
1060
+ */
1061
+ el.goToSlide = function(slideIndex, direction){
1062
+ // if plugin is currently in motion, ignore request
1063
+ if(slider.working || slider.active.index == slideIndex) return;
1064
+ // declare that plugin is in motion
1065
+ slider.working = true;
1066
+ // store the old index
1067
+ slider.oldIndex = slider.active.index;
1068
+ // if slideIndex is less than zero, set active index to last child (this happens during infinite loop)
1069
+ if(slideIndex < 0){
1070
+ slider.active.index = getPagerQty() - 1;
1071
+ // if slideIndex is greater than children length, set active index to 0 (this happens during infinite loop)
1072
+ }else if(slideIndex >= getPagerQty()){
1073
+ slider.active.index = 0;
1074
+ // set active index to requested slide
1075
+ }else{
1076
+ slider.active.index = slideIndex;
1077
+ }
1078
+ // onSlideBefore, onSlideNext, onSlidePrev callbacks
1079
+ slider.settings.onSlideBefore(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index);
1080
+ if(direction == 'next'){
1081
+ slider.settings.onSlideNext(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index);
1082
+ }else if(direction == 'prev'){
1083
+ slider.settings.onSlidePrev(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index);
1084
+ }
1085
+ // check if last slide
1086
+ slider.active.last = slider.active.index >= getPagerQty() - 1;
1087
+ // update the pager with active class
1088
+ if(slider.settings.pager) updatePagerActive(slider.active.index);
1089
+ // // check for direction control update
1090
+ if(slider.settings.controls) updateDirectionControls();
1091
+ // if slider is set to mode: "fade"
1092
+ if(slider.settings.mode == 'fade'){
1093
+ // if adaptiveHeight is true and next height is different from current height, animate to the new height
1094
+ if(slider.settings.adaptiveHeight && slider.viewport.height() != getViewportHeight()){
1095
+ slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed);
1096
+ }
1097
+ // fade out the visible child and reset its z-index value
1098
+ slider.children.filter(':visible').fadeOut(slider.settings.speed).css({zIndex: 0});
1099
+ // fade in the newly requested slide
1100
+ slider.children.eq(slider.active.index).css('zIndex', 51).fadeIn(slider.settings.speed, function(){
1101
+ $(this).css('zIndex', 50);
1102
+ updateAfterSlideTransition();
1103
+ });
1104
+ // slider mode is not "fade"
1105
+ }else{
1106
+ // if adaptiveHeight is true and next height is different from current height, animate to the new height
1107
+ if(slider.settings.adaptiveHeight && slider.viewport.height() != getViewportHeight()){
1108
+ slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed);
1109
+ }
1110
+ var moveBy = 0;
1111
+ var position = {left: 0, top: 0};
1112
+ // if carousel and not infinite loop
1113
+ if(!slider.settings.infiniteLoop && slider.carousel && slider.active.last){
1114
+ if(slider.settings.mode == 'horizontal'){
1115
+ // get the last child position
1116
+ var lastChild = slider.children.eq(slider.children.length - 1);
1117
+ position = lastChild.position();
1118
+ // calculate the position of the last slide
1119
+ moveBy = slider.viewport.width() - lastChild.width();
1120
+ }else{
1121
+ // get last showing index position
1122
+ var lastShowingIndex = slider.children.length - slider.settings.minSlides;
1123
+ position = slider.children.eq(lastShowingIndex).position();
1124
+ }
1125
+ // horizontal carousel, going previous while on first slide (infiniteLoop mode)
1126
+ }else if(slider.carousel && slider.active.last && direction == 'prev'){
1127
+ // get the last child position
1128
+ var eq = slider.settings.moveSlides == 1 ? slider.settings.maxSlides - getMoveBy() : ((getPagerQty() - 1) * getMoveBy()) - (slider.children.length - slider.settings.maxSlides);
1129
+ var lastChild = el.children('.bx-clone').eq(eq);
1130
+ position = lastChild.position();
1131
+ // if infinite loop and "Next" is clicked on the last slide
1132
+ }else if(direction == 'next' && slider.active.index == 0){
1133
+ // get the last clone position
1134
+ position = el.find('> .bx-clone').eq(slider.settings.maxSlides).position();
1135
+ slider.active.last = false;
1136
+ // normal non-zero requests
1137
+ }else if(slideIndex >= 0){
1138
+ var requestEl = slideIndex * getMoveBy();
1139
+ position = slider.children.eq(requestEl).position();
1140
+ }
1141
+
1142
+ /* If the position doesn't exist
1143
+ * (e.g. if you destroy the slider on a next click),
1144
+ * it doesn't throw an error.
1145
+ */
1146
+ if ("undefined" !== typeof(position)) {
1147
+ var value = slider.settings.mode == 'horizontal' ? -(position.left - moveBy) : -position.top;
1148
+ // plugin values to be animated
1149
+ setPositionProperty(value, 'slide', slider.settings.speed);
1150
+ }
1151
+ }
1152
+ }
1153
+
1154
+ /**
1155
+ * Transitions to the next slide in the show
1156
+ */
1157
+ el.goToNextSlide = function(){
1158
+ // if infiniteLoop is false and last page is showing, disregard call
1159
+ if (!slider.settings.infiniteLoop && slider.active.last) return;
1160
+ var pagerIndex = parseInt(slider.active.index) + 1;
1161
+ el.goToSlide(pagerIndex, 'next');
1162
+ }
1163
+
1164
+ /**
1165
+ * Transitions to the prev slide in the show
1166
+ */
1167
+ el.goToPrevSlide = function(){
1168
+ // if infiniteLoop is false and last page is showing, disregard call
1169
+ if (!slider.settings.infiniteLoop && slider.active.index == 0) return;
1170
+ var pagerIndex = parseInt(slider.active.index) - 1;
1171
+ el.goToSlide(pagerIndex, 'prev');
1172
+ }
1173
+
1174
+ /**
1175
+ * Starts the auto show
1176
+ *
1177
+ * @param preventControlUpdate (boolean)
1178
+ * - if true, auto controls state will not be updated
1179
+ */
1180
+ el.startAuto = function(preventControlUpdate){
1181
+ // if an interval already exists, disregard call
1182
+ if(slider.interval) return;
1183
+ // create an interval
1184
+ slider.interval = setInterval(function(){
1185
+ slider.settings.autoDirection == 'next' ? el.goToNextSlide() : el.goToPrevSlide();
1186
+ }, slider.settings.pause);
1187
+ // if auto controls are displayed and preventControlUpdate is not true
1188
+ if (slider.settings.autoControls && preventControlUpdate != true) updateAutoControls('stop');
1189
+ }
1190
+
1191
+ /**
1192
+ * Stops the auto show
1193
+ *
1194
+ * @param preventControlUpdate (boolean)
1195
+ * - if true, auto controls state will not be updated
1196
+ */
1197
+ el.stopAuto = function(preventControlUpdate){
1198
+ // if no interval exists, disregard call
1199
+ if(!slider.interval) return;
1200
+ // clear the interval
1201
+ clearInterval(slider.interval);
1202
+ slider.interval = null;
1203
+ // if auto controls are displayed and preventControlUpdate is not true
1204
+ if (slider.settings.autoControls && preventControlUpdate != true) updateAutoControls('start');
1205
+ }
1206
+
1207
+ /**
1208
+ * Returns current slide index (zero-based)
1209
+ */
1210
+ el.getCurrentSlide = function(){
1211
+ return slider.active.index;
1212
+ }
1213
+
1214
+ /**
1215
+ * Returns number of slides in show
1216
+ */
1217
+ el.getSlideCount = function(){
1218
+ return slider.children.length;
1219
+ }
1220
+
1221
+ /**
1222
+ * Update all dynamic slider elements
1223
+ */
1224
+ el.redrawSlider = function(){
1225
+ // resize all children in ratio to new screen size
1226
+ slider.children.add(el.find('.bx-clone')).width(getSlideWidth());
1227
+ // adjust the height
1228
+ slider.viewport.css('height', getViewportHeight());
1229
+ // update the slide position
1230
+ if(!slider.settings.ticker) setSlidePosition();
1231
+ // if active.last was true before the screen resize, we want
1232
+ // to keep it last no matter what screen size we end on
1233
+ if (slider.active.last) slider.active.index = getPagerQty() - 1;
1234
+ // if the active index (page) no longer exists due to the resize, simply set the index as last
1235
+ if (slider.active.index >= getPagerQty()) slider.active.last = true;
1236
+ // if a pager is being displayed and a custom pager is not being used, update it
1237
+ if(slider.settings.pager && !slider.settings.pagerCustom){
1238
+ populatePager();
1239
+ updatePagerActive(slider.active.index);
1240
+ }
1241
+ }
1242
+
1243
+ /**
1244
+ * Destroy the current instance of the slider (revert everything back to original state)
1245
+ */
1246
+ el.destroySlider = function(){
1247
+ // don't do anything if slider has already been destroyed
1248
+ if(!slider.initialized) return;
1249
+ slider.initialized = false;
1250
+ $('.bx-clone', this).remove();
1251
+ slider.children.removeAttr('style');
1252
+ this.removeAttr('style').unwrap().unwrap();
1253
+ if(slider.controls.el) slider.controls.el.remove();
1254
+ if(slider.controls.next) slider.controls.next.remove();
1255
+ if(slider.controls.prev) slider.controls.prev.remove();
1256
+ if(slider.pagerEl) slider.pagerEl.remove();
1257
+ $('.bx-caption', this).remove();
1258
+ if(slider.controls.autoEl) slider.controls.autoEl.remove();
1259
+ clearInterval(slider.interval);
1260
+ $(window).unbind('resize', resizeWindow);
1261
+ }
1262
+
1263
+ /**
1264
+ * Reload the slider (revert all DOM changes, and re-initialize)
1265
+ */
1266
+ el.reloadSlider = function(settings){
1267
+ if (settings != undefined) options = settings;
1268
+ el.destroySlider();
1269
+ init();
1270
+ }
1271
+
1272
+ init();
1273
+
1274
+ // returns the current jQuery object
1275
+ return this;
1276
+ }
1277
+
1278
+ })(jQuery);
1279
+
1280
+ /*!
1281
+ * jQuery imagesLoaded plugin v2.1.0
1282
+ * http://github.com/desandro/imagesloaded
1283
+ *
1284
+ * MIT License. by Paul Irish et al.
1285
+ */
1286
+
1287
+ /*jshint curly: true, eqeqeq: true, noempty: true, strict: true, undef: true, browser: true */
1288
+ /*global jQuery: false */
1289
+
1290
+ (function(c,n){var l="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";c.fn.imagesLoaded=function(f){function m(){var b=c(i),a=c(h);d&&(h.length?d.reject(e,b,a):d.resolve(e));c.isFunction(f)&&f.call(g,e,b,a)}function j(b,a){b.src===l||-1!==c.inArray(b,k)||(k.push(b),a?h.push(b):i.push(b),c.data(b,"imagesLoaded",{isBroken:a,src:b.src}),o&&d.notifyWith(c(b),[a,e,c(i),c(h)]),e.length===k.length&&(setTimeout(m),e.unbind(".imagesLoaded")))}var g=this,d=c.isFunction(c.Deferred)?c.Deferred():
1291
+ 0,o=c.isFunction(d.notify),e=g.find("img").add(g.filter("img")),k=[],i=[],h=[];c.isPlainObject(f)&&c.each(f,function(b,a){if("callback"===b)f=a;else if(d)d[b](a)});e.length?e.bind("load.imagesLoaded error.imagesLoaded",function(b){j(b.target,"error"===b.type)}).each(function(b,a){var d=a.src,e=c.data(a,"imagesLoaded");if(e&&e.src===d)j(a,e.isBroken);else if(a.complete&&a.naturalWidth!==n)j(a,0===a.naturalWidth||0===a.naturalHeight);else if(a.readyState||a.complete)a.src=l,a.src=d}):m();return d?d.promise(g):
1292
+ g}})(jQuery);