1 2(function($) { 3$.jCarouselLite = { 4 version: '1.8.7', 5 curr: 0 6}; 7 8$.fn.jCarouselLite = function(options) { 9 var o = $.extend(true, {}, $.fn.jCarouselLite.defaults, options), 10 ceil = Math.ceil, 11 mabs = Math.abs; 12 13 this.each(function() { 14 15 var beforeCirc, afterCirc, pageNav, pageNavCount, resize, 16 prepResize, touchEvents, $btnsGo, 17 isTouch = 'ontouchend' in document, 18 styles = { div: {}, ul: {}, li: {} }, 19 firstCss = true, 20 running = false, 21 animCss = o.vertical ? 'top': 'left', 22 aniProps = {}, 23 sizeProp = o.vertical ? 'height': 'width', 24 outerMethod = o.vertical ? 'outerHeight': 'outerWidth', 25 self = this, 26 div = $(this), 27 ul = div.find('ul').eq(0), 28 tLi = ul.children('li'), 29 tl = tLi.length, 30 visibleNum = o.visible, 31 // need visibleCeil and visibleFloor in case we want a fractional number of visible items at a time 32 visibleCeil = ceil(visibleNum), 33 visibleFloor = Math.floor(visibleNum), 34 start = Math.min(o.start, tl - 1), 35 direction = 1, 36 activeBtnOffset = 0, 37 activeBtnTypes = {}, 38 startTouch = {}, 39 endTouch = {}, 40 axisPrimary = o.vertical ? 'y' : 'x', 41 axisSecondary = o.vertical ? 'x' : 'y'; 42 43 44 var init = o.init.call(this, o, tLi); 45 // bail out for this carousel if the o.init() callback returns `false` 46 if ( init === false ) { 47 return; 48 } 49 50 div.data('dirjc', direction); 51 div.data(animCss + 'jc', div.css(animCss)); 52 53 if (o.circular) { 54 55 beforeCirc = tLi.slice( tl - visibleCeil ).clone(true).each(fixIds); 56 afterCirc = tLi.slice( 0, visibleCeil ).clone(true).each(fixIds); 57 ul.prepend( beforeCirc ) 58 .append( afterCirc ); 59 start += visibleCeil; 60 activeBtnOffset = visibleCeil; 61 62 } 63 64 if (o.btnGo && o.btnGo.length) { 65 66 if ( $.isArray(o.btnGo) && typeof o.btnGo[0] === 'string' ) { 67 $btnsGo = $( o.btnGo.join() ); 68 } else { 69 $btnsGo = $(o.btnGo); 70 } 71 72 $btnsGo.each(function(i) { 73 $(this).bind('click.jc', function(event) { 74 event.preventDefault(); 75 return go(o.circular ? visibleNum + i : i); 76 }); 77 }); 78 activeBtnTypes.go = 1; 79 } 80 81 var setActiveBtn = function(i, types) { 82 i = ceil(i); 83 84 var activeBtnIndex = (i - activeBtnOffset) % tl, 85 visEnd = activeBtnIndex + visibleFloor; 86 87 if ( types.go ) { 88 // remove active and visible classes from all the go buttons 89 $btnsGo.removeClass(o.activeClass).removeClass(o.visibleClass); 90 // add active class to the go button corresponding to the first visible slide 91 $btnsGo.eq(activeBtnIndex).addClass(o.activeClass); 92 // add visible class to go buttons corresponding to all visible slides 93 $btnsGo.slice(activeBtnIndex, activeBtnIndex + visibleFloor).addClass(o.visibleClass); 94 95 if ( visEnd > $btnsGo.length ) { 96 $btnsGo.slice(0, visEnd - $btnsGo.length).addClass(o.visibleClass); 97 } 98 } 99 100 if ( types.pager ) { 101 pageNav.removeClass(o.activeClass); 102 pageNav.eq( ceil(activeBtnIndex / visibleNum) ).addClass(o.activeClass); 103 } 104 return activeBtnIndex; 105 }; 106 107 var li = ul.children('li'), 108 itemLength = li.length, 109 curr = start; 110 111 $.jCarouselLite.curr = curr; 112 113 var getDimensions = function(reset) { 114 var liSize, ulSize, divSize; 115 116 if (reset) { 117 118 styles.div[sizeProp] = ''; 119 styles.li = { 120 width: '', height: '' 121 }; 122 // bail out with the reset styles 123 return styles; 124 } 125 126 // Full li size(incl margin)-Used for animation 127 liSize = li[outerMethod](true); 128 129 // size of full ul(total length, not just for the visible items) 130 ulSize = liSize * itemLength; 131 132 // size of entire div(total length for just the visible items) 133 divSize = liSize * visibleNum; 134 135 styles.div[sizeProp] = divSize + 'px'; 136 styles.ul[sizeProp] = ulSize + 'px'; 137 styles.ul[animCss] = -(curr * liSize) + 'px'; 138 styles.li = { 139 width: li.width(), height: li.height() 140 }; 141 styles.liSize = liSize; 142 return styles; 143 }; 144 145 146 var setDimensions = function(reset) { 147 var css, tmpDivSize; 148 var prelimCss = { 149 div: {visibility: 'visible', position: 'relative', zIndex: 2, left: '0'}, 150 ul: {margin: '0', padding: '0', position: 'relative', listStyleType: 'none', zIndex: 1}, 151 li: {overflow: o.vertical ? 'hidden' : 'visible', 'float': o.vertical ? 'none' : 'left'} 152 }; 153 154 if (reset) { 155 css = getDimensions(true); 156 div.css(css.div); 157 ul.css(css.ul); 158 li.css(css.li); 159 } 160 161 css = getDimensions(); 162 163 if (o.autoCSS && firstCss) { 164 $.extend(true, css, prelimCss); 165 firstCss = false;
166 } 167 168 if (o.autoWidth) { 169 tmpDivSize = parseInt(div.css(sizeProp), 10); 170 styles.liSize = tmpDivSize / o.visible; 171 css.li[sizeProp] = styles.liSize - (li[outerMethod](true) - parseInt(li.css(sizeProp), 10)); 172 173 // Need to adjust other settings to fit with li width 174 css.ul[sizeProp] = (styles.liSize * itemLength) + 'px'; 175 css.ul[animCss] = -(curr * styles.liSize) + 'px'; 176 css.div[sizeProp] = tmpDivSize; 177 } 178 179 if (o.autoCSS) { 180 li.css(css.li); 181 ul.css(css.ul); 182 div.css(css.div); 183 } 184 }; 185 186 setDimensions(); 187 188 // set up timed advancer 189 var advanceCounter = 0, 190 autoStop = iterations(tl, o), 191 autoScrollBy = typeof o.auto === 'number' ? o.auto : o.scroll; 192 193 var advancer = function() { 194 self.setAutoAdvance = setTimeout(function() { 195 196 if (!autoStop || autoStop > advanceCounter) { 197 direction = div.data('dirjc'); 198 go( curr + (direction * autoScrollBy), {auto: true} ); 199 advanceCounter++; 200 advancer(); 201 } 202 }, o.timeout); 203 }; 204 205 // bind click handlers to prev and next buttons, if set 206 $.each([ 'btnPrev', 'btnNext' ], function(index, btn) { 207 if ( o[btn] ) { 208 o['$' + btn] = $.isFunction( o[btn] ) ? o[btn].call( div[0] ) : $( o[btn] ); 209 o['$' + btn].bind('click.jc', function(event) { 210 event.preventDefault(); 211 var step = index === 0 ? curr - o.scroll : curr + o.scroll; 212 if (o.directional) { 213 // set direction of subsequent scrolls to: 214 // 1 if "btnNext" clicked 215 // -1 if "btnPrev" clicked 216 div.data( 'dirjc', (index ? 1 : -1) ); 217 } 218 return go( step ); 219 }); 220 } 221 }); 222 223 if (!o.circular) { 224 if (o.btnPrev && start === 0) { 225 o.$btnPrev.addClass(o.btnDisabledClass); 226 } 227 228 if ( o.btnNext && start + visibleFloor >= itemLength ) { 229 o.$btnNext.addClass(o.btnDisabledClass); 230 } 231 } 232 233 if (o.autoPager) { 234 pageNavCount = ceil(tl / visibleNum); 235 pageNav = []; 236 for (var i=0; i < pageNavCount; i++) { 237 pageNav.push('<li><a href="#">' + (i+1) + '</a></li>'); 238 } 239 if (pageNav.length > 1) { 240 pageNav = $('<ul>' + pageNav.join('') + '</ul>').appendTo(o.autoPager).find('li'); 241 pageNav.find('a').each(function(i) { 242 $(this).bind('click.jc', function(event) { 243 event.preventDefault(); 244 var slide = i * visibleNum; 245 if (o.circular) { 246 slide += visibleNum; 247 } 248 return go(slide); 249 }); 250 }); 251 activeBtnTypes.pager = 1; 252 } 253 } 254 255 // set the active class on the btn corresponding to the "start" li 256 setActiveBtn(start, activeBtnTypes); 257 258 if (o.mouseWheel && div.mousewheel) { 259 div.bind('mousewheel.jc', function(e, d) { 260 return d > 0 ? go(curr - o.scroll) : go(curr + o.scroll); 261 }); 262 } 263 264 if (o.pause && o.auto && !isTouch) { 265 div.bind('mouseenter.jc', function() { 266 div.trigger('pauseCarousel.jc'); 267 }).bind('mouseleave.jc', function() { 268 div.trigger('resumeCarousel.jc'); 269 }); 270 } 271 272 if (o.auto) { 273 advancer(); 274 } 275 276 function vis() { 277 return li.slice(curr).slice(0, visibleCeil); 278 } 279 280 $.jCarouselLite.vis = vis; 281 282 function go(to, settings) { 283 if (running) { return false; } 284 settings = settings || {}; 285 var prev = curr, 286 direction = to > curr, 287 speed = settings.speed || o.speed, 288 // offset appears if touch moves slides 289 offset = settings.offset || 0; 290 291 292 if (o.beforeStart) { 293 o.beforeStart.call(div, vis(), direction); 294 } 295 296 li.removeClass(o.activeClass); 297 298 // If circular and we are in first or last, then go to the other end 299 if (o.circular) { 300 if (to > curr && to > itemLength - visibleCeil) { 301 curr = curr % tl; 302 to = curr + (settings.auto ? autoScrollBy : o.scroll); 303 ul.css(animCss, (-curr * styles.liSize) - offset); 304 } else if ( to < curr && to < 0) { 305 curr += tl; 306 to += tl; 307 ul.css(animCss, (-curr * styles.liSize) - offset); 308 } 309 310 curr = to + (to % 1); 311 312 // If non-circular and "to" points beyond first or last, we change to first or last. 313 } else { 314 if (to < 0) { 315 to = 0; 316 } else if (to > itemLength - visibleFloor) { 317 to = itemLength - visibleFloor; 318 } 319 320 curr = to; 321 322 if (curr === 0 && o.first) { 323 o.first.call(this, vis(), direction); 324 } 325 326 if (curr === itemLength - visibleFloor && o.last) { 327 o.last.call(this, vis(), direction); 328 } 329 330 // Disable buttons when the carousel reaches the last/first, and enable when not 331 if (o.btnPrev) {
332 o.$btnPrev.toggleClass(o.btnDisabledClass, curr === 0); 333 } 334 if (o.btnNext) { 335 o.$btnNext.toggleClass(o.btnDisabledClass, curr === itemLength - visibleFloor); 336 } 337 } 338 339 // if btnGo, set the active class on the btnGo element corresponding to the first visible carousel li 340 // if autoPager, set active class on the appropriate autopager element 341 setActiveBtn(curr, activeBtnTypes); 342 343 $.jCarouselLite.curr = curr; 344 345 if (prev === curr && !settings.force) { 346 if (o.afterEnd) { 347 o.afterEnd.call(div, vis(), direction); 348 } 349 return curr; 350 } 351 352 running = true; 353 354 aniProps[animCss] = -(curr * styles.liSize); 355 ul.animate(aniProps, speed, o.easing, function() { 356 if (o.afterEnd) { 357 o.afterEnd.call(div, vis(), direction); 358 } 359 running = false; 360 }); 361 362 li.eq(curr).addClass(o.activeClass); 363 364 return curr; 365 } // end go function 366 367 // bind custom events so they can be triggered by user 368 div 369 .bind('go.jc', function(e, to, settings) { 370 371 if (typeof to === 'undefined') { 372 to = '+=1'; 373 } 374 375 var todir = typeof to === 'string' && /(\+=|-=)(\d+)/.exec(to); 376 377 if ( todir ) { 378 to = todir[1] === '-=' ? curr - todir[2] * 1 : curr + todir[2] * 1; 379 } else { 380 to += start; 381 } 382 go(to, settings); 383 }) 384 .bind('startCarousel.jc', function(event) { 385 clearTimeout(self.setAutoAdvance); 386 self.setAutoAdvance = undefined; 387 div.trigger('go', '+=' + o.scroll); 388 advancer(); 389 div.removeData('pausedjc').removeData('stoppedjc'); 390 }) 391 .bind('resumeCarousel.jc', function(event, forceRun) { 392 if (self.setAutoAdvance) { return; } 393 clearTimeout(self.setAutoAdvance); 394 self.setAutoAdvance = undefined; 395 396 var stopped = div.data('stoppedjc'); 397 if ( forceRun || !stopped ) { 398 advancer(); 399 div.removeData('pausedjc'); 400 if (stopped) { 401 div.removeData('stoppedjc'); 402 } 403 } 404 }) 405 406 .bind('pauseCarousel.jc', function(event) { 407 clearTimeout(self.setAutoAdvance); 408 self.setAutoAdvance = undefined; 409 div.data('pausedjc', true); 410 }) 411 .bind('stopCarousel.jc', function(event) { 412 clearTimeout(self.setAutoAdvance); 413 self.setAutoAdvance = undefined; 414 415 div.data('stoppedjc', true); 416 }) 417 418 .bind('refreshCarousel.jc', function(event) { 419 setDimensions(o.autoCSS); 420 }) 421 422 .bind('endCarousel.jc', function() { 423 if (self.setAutoAdvance) { 424 clearTimeout(self.setAutoAdvance); 425 self.setAutoAdvance = undefined; 426 } 427 if (o.btnPrev) { 428 o.$btnPrev.addClass(o.btnDisabledClass).unbind('.jc'); 429 } 430 if (o.btnNext) { 431 o.$btnNext.addClass(o.btnDisabledClass).unbind('.jc'); 432 } 433 if (o.btnGo) { 434 $.each(o.btnGo, function(i, val) { 435 $(val).unbind('.jc'); 436 }); 437 } 438 439 if (o.circular) { 440 li.slice(0, visibleCeil).remove(); 441 li.slice(-visibleCeil).remove(); 442 } 443 $.each([animCss + 'jc', 'pausedjc', 'stoppedjc', 'dirjc'], function(i, d) { 444 div.removeData(d); 445 }); 446 div.unbind('.jc'); 447 }); 448 449 // touch gesture support 450 451 touchEvents = { 452 touchstart: function(event) { 453 endTouch.x = 0; 454 endTouch.y = 0; 455 startTouch.x = event.targetTouches[0].pageX; 456 startTouch.y = event.targetTouches[0].pageY; 457 startTouch[animCss] = parseFloat( ul.css(animCss) ); 458 startTouch.time = +new Date(); 459 }, 460 461 touchmove: function(event) { 462 var tlength = event.targetTouches.length; 463 464 if (tlength === 1) { 465 event.preventDefault(); 466 endTouch.x = event.targetTouches[0].pageX; 467 endTouch.y = event.targetTouches[0].pageY; 468 aniProps[animCss] = startTouch[animCss] + (endTouch[axisPrimary] - startTouch[axisPrimary]); 469 ul.css(aniProps); 470 } else { 471 endTouch.x = startTouch.x; 472 endTouch.y = startTouch.y; 473 } 474 }, 475 476 touchend: function(event) { 477 // bail out early if there is no touch movement 478 if (!endTouch.x) { 479 return; 480 } 481 482 var pxDelta = startTouch[axisPrimary] - endTouch[axisPrimary], 483 pxAbsDelta = mabs( pxDelta ), 484 primaryAxisGood = pxAbsDelta > o.swipeThresholds[axisPrimary], 485 secondaryAxisGood = mabs(startTouch[axisSecondary] - endTouch[axisSecondary]) < o.swipeThresholds[axisSecondary], 486 timeDelta = +new Date() - startTouch.time, 487 quickSwipe = timeDelta < o.swipeThresholds.time, 488 operator = pxDelta > 0 ? '+=' : '-=', 489 to = operator + o.scroll, 490 swipeInfo = { force: true }; 491 492 // quick, clean swipe 493 if ( quickSwipe && primaryAxisGood && secondaryAxisGood ) { 494 // set animation speed to twice as fast as that set in speed option 495 swipeInfo.speed = o.speed / 2; 496 } 497 else
498 // slow swipe < 1/2 slide width, OR 499 // not enough movement for swipe, OR 500 // too much movement on secondary axis when quick swipe 501 if ( (!quickSwipe && pxAbsDelta < styles.liSize / 2) || 502 !primaryAxisGood || 503 (quickSwipe && !secondaryAxisGood) 504 ) { 505 // revert to same slide 506 to = '+=0'; 507 } 508 else 509 // slow swipe > 1/2 slide width 510 if ( !quickSwipe && pxAbsDelta > styles.liSize / 2 ) { 511 to = Math.round(pxAbsDelta / styles.liSize); 512 to = operator + (to > o.visible ? o.visible : to); 513 514 // send pxDelta along as offset in case carousel is circular and needs to reset 515 swipeInfo.offset = pxDelta; 516 } 517 518 div.trigger('go.jc', [to, swipeInfo]); 519 endTouch = {}; 520 }, 521 522 handle: function(event) { 523 event = event.originalEvent; 524 touchEvents[event.type](event); 525 } 526 }; 527 528 if ( isTouch && o.swipe ) { 529 div.bind('touchstart.jc touchmove.jc touchend.jc', touchEvents.handle); 530 } // end swipe events 531 532 // Responsive design handling: 533 // Reset dimensions on window.resize 534 if (o.responsive) { 535 prepResize = o.autoCSS; 536 $(window).bind('resize', function(event) { 537 if (prepResize) { 538 ul.width( ul.width() * 2 ); 539 prepResize = false; 540 } 541 542 clearTimeout(resize); 543 resize = setTimeout(function() { 544 div.trigger('refreshCarousel.jc'); 545 prepResize = o.autoCSS; 546 }, 100); 547 548 }); 549 } 550 551 552 553 }); // end each 554 555 return this; 556}; 557 558$.fn.jCarouselLite.defaults = { 559 btnPrev: null, 560 btnNext: null, 561 562 // array (or jQuery object) of elements. When clicked, makes the corresponding carousel LI the first visible one 563 btnGo: null, 564 565 // selector (or jQuery object) indicating the containing element for pagination navigation. 566 autoPager: null, 567 btnDisabledClass: 'disabled', 568 569 // class applied to the active slide and btnGo element 570 activeClass: 'active', 571 572 // class applied to the btnGo elements corresponding to the visible slides 573 visibleClass: 'vis', 574 mouseWheel: false, 575 speed: 200, 576 easing: null, 577 578 // milliseconds between scrolls 579 timeout: 4000, 580 581 // true to enable auto scrolling; number to auto-scroll by different number at a time than that of scroll option 582 auto: false, 583 584 585 // true to enable changing direction of auto scrolling when user clicks prev or next button 586 directional: false, 587 588 // number of times before autoscrolling will stop. (if circular is false, won't iterate more than number of items) 589 autoStop: false, 590 591 // pause scrolling on hover 592 pause: true, 593 vertical: false, 594 595 // continue scrolling when reach the last item 596 circular: true, 597 598 // the number to be visible at a given time. 599 visible: 3, 600 601 // index of item to show initially in the first posiition 602 start: 0, 603 604 // number of items to scroll at a time 605 scroll: 1, 606 607 // whether to set initial styles on the carousel elements. See readme for info 608 autoCSS: true, 609 610 // whether the dimensions should change on resize 611 responsive: false, 612 613 // whether to set width of <li>s (and left/top of <ul>) based on width of <div> 614 autoWidth: false, 615 616 // touch options 617 swipe: true, 618 swipeThresholds: { 619 x: 80, 620 y: 40, 621 time: 150 622 }, 623 624 // Function to be called for each matched carousel when .jCaourselLite() is called. 625 // Inside the function, `this` is the carousel div. 626 // The function can take 2 arguments: 627 // 1. The merged options object 628 // 2. A jQuery object containing the <li> items in the carousel 629 // If the function returns `false`, the plugin will skip all the carousel magic for that carousel div 630 init: function() {}, 631 632 // function to be called once the first slide is hit 633 first: null, 634 635 // function to be called once the last slide is hit 636 last: null, 637 638 // function to be called before each transition starts 639 beforeStart: null, 640 641 // function to be called after each transition ends 642 afterEnd: null 643}; 644 645function iterations(itemLength, options) { 646 return options.autoStop && (options.circular ? options.autoStop : Math.min(itemLength, options.autoStop)); 647} 648 649function fixIds(i) { 650 if ( this.id ) { 651 this.id += i; 652 } 653} 654})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.