bxslider-rails 4.2.3 → 4.2.4

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