1/*! 2 * jCarousel - Riding carousels with jQuery 3 * http://sorgalla.com/jcarousel/ 4 * 5 * Copyright (c) 2006 Jan Sorgalla (http://sorgalla.com) 6 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 7 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 8 * 9 * Built on top of the jQuery library 10 * http://jquery.com 11 * 12 * Inspired by the "Carousel Component" by Bill Scott 13 * http://billwscott.com/carousel/ 14 */ 15 16/*global window, jQuery */ 17(function($) { 18 // Default configuration properties. 19 var defaults = { 20 vertical: false, 21 rtl: false, 22 start: 1, 23 offset: 1, 24 size: null, 25 scroll: 3, 26 visible: null, 27 animation: 'normal', 28 easing: 'swing', 29 auto: 0, 30 wrap: null, 31 initCallback: null, 32 setupCallback: null, 33 reloadCallback: null, 34 itemLoadCallback: null, 35 itemFirstInCallback: null, 36 itemFirstOutCallback: null, 37 itemLastInCallback: null, 38 itemLastOutCallback: null, 39 itemVisibleInCallback: null, 40 itemVisibleOutCallback: null, 41 animationStepCallback: null, 42 buttonNextHTML: '<div></div>', 43 buttonPrevHTML: '<div></div>', 44 buttonNextEvent: 'click', 45 buttonPrevEvent: 'click', 46 buttonNextCallback: null, 47 buttonPrevCallback: null, 48 itemFallbackDimension: null 49 }, windowLoaded = false; 50 51 $(window).bind('load.jcarousel', function() { windowLoaded = true; }); 52 53 /** 54 * The jCarousel object. 55 * 56 * @constructor 57 * @class jcarousel 58 * @param e {HTMLElement} The element to create the carousel for. 59 * @param o {Object} A set of key/value pairs to set as configuration properties. 60 * @cat Plugins/jCarousel 61 */ 62 $.jcarousel = function(e, o) { 63 this.options = $.extend({}, defaults, o || {}); 64 65 this.locked = false; 66 this.autoStopped = false; 67 68 this.container = null; 69 this.clip = null; 70 this.list = null; 71 this.buttonNext = null; 72 this.buttonPrev = null; 73 this.buttonNextState = null; 74 this.buttonPrevState = null; 75 76 // Only set if not explicitly passed as option 77 if (!o || o.rtl === undefined) { 78 this.options.rtl = ($(e).attr('dir') || $('html').attr('dir') || '').toLowerCase() == 'rtl'; 79 } 80 81 this.wh = !this.options.vertical ? 'width' : 'height'; 82 this.lt = !this.options.vertical ? (this.options.rtl ? 'right' : 'left') : 'top'; 83 84 // Extract skin class 85 var skin = '', split = e.className.split(' '); 86 87 for (var i = 0; i < split.length; i++) { 88 if (split[i].indexOf('jcarousel-skin') != -1) { 89 $(e).removeClass(split[i]); 90 skin = split[i]; 91 break; 92 } 93 } 94 95 if (e.nodeName.toUpperCase() == 'UL' || e.nodeName.toUpperCase() == 'OL') { 96 this.list = $(e); 97 this.clip = this.list.parents('.jcarousel-clip'); 98 this.container = this.list.parents('.jcarousel-container'); 99 } else { 100 this.container = $(e); 101 this.list = this.container.find('ul,ol').eq(0); 102 this.clip = this.container.find('.jcarousel-clip'); 103 } 104 105 if (this.clip.size() === 0) { 106 this.clip = this.list.wrap('<div></div>').parent(); 107 } 108 109 if (this.container.size() === 0) { 110 this.container = this.clip.wrap('<div></div>').parent(); 111 } 112 113 if (skin !== '' && this.container.parent()[0].className.indexOf('jcarousel-skin') == -1) { 114 this.container.wrap('<div class=" '+ skin + '"></div>'); 115 } 116 117 this.buttonPrev = $('.jcarousel-prev', this.container); 118 119 if (this.buttonPrev.size() === 0 && this.options.buttonPrevHTML !== null) { 120 this.buttonPrev = $(this.options.buttonPrevHTML).appendTo(this.container); 121 } 122 123 this.buttonPrev.addClass(this.className('jcarousel-prev')); 124 125 this.buttonNext = $('.jcarousel-next', this.container); 126 127 if (this.buttonNext.size() === 0 && this.options.buttonNextHTML !== null) { 128 this.buttonNext = $(this.options.buttonNextHTML).appendTo(this.container); 129 } 130 131 this.buttonNext.addClass(this.className('jcarousel-next')); 132 133 this.clip.addClass(this.className('jcarousel-clip')).css({ 134 position: 'relative' 135 }); 136 137 this.list.addClass(this.className('jcarousel-list')).css({ 138 overflow: 'hidden', 139 position: 'relative', 140 top: 0, 141 margin: 0, 142 padding: 0 143 }).css((this.options.rtl ? 'right' : 'left'), 0); 144 145 this.container.addClass(this.className('jcarousel-container')).css({ 146 position: 'relative' 147 }); 148 149 if (!this.options.vertical && this.options.rtl) {
150 this.container.addClass('jcarousel-direction-rtl').attr('dir', 'rtl'); 151 } 152 153 var di = this.options.visible !== null ? Math.ceil(this.clipping() / this.options.visible) : null; 154 var li = this.list.children('li'); 155 156 var self = this; 157 158 if (li.size() > 0) { 159 var wh = 0, j = this.options.offset; 160 li.each(function() { 161 self.format(this, j++); 162 wh += self.dimension(this, di); 163 }); 164 165 this.list.css(this.wh, (wh + 100) + 'px'); 166 167 // Only set if not explicitly passed as option 168 if (!o || o.size === undefined) { 169 this.options.size = li.size(); 170 } 171 } 172 173 // For whatever reason, .show() does not work in Safari... 174 this.container.css('display', 'block'); 175 this.buttonNext.css('display', 'block'); 176 this.buttonPrev.css('display', 'block'); 177 178 this.funcNext = function() { self.next(); return false; }; 179 this.funcPrev = function() { self.prev(); return false; }; 180 this.funcResize = function() { 181 if (self.resizeTimer) { 182 clearTimeout(self.resizeTimer); 183 } 184 185 self.resizeTimer = setTimeout(function() { 186 self.reload(); 187 }, 100); 188 }; 189 190 if (this.options.initCallback !== null) { 191 this.options.initCallback(this, 'init'); 192 } 193 194 if (!windowLoaded && $jc.isSafari()) { 195 this.buttons(false, false); 196 $(window).bind('load.jcarousel', function() { self.setup(); }); 197 } else { 198 this.setup(); 199 } 200 }; 201 202 // Create shortcut for internal use 203 var $jc = $.jcarousel; 204 205 $jc.fn = $jc.prototype = { 206 jcarousel: '0.2.9' 207 }; 208 209 $jc.fn.extend = $jc.extend = $.extend; 210 211 $jc.fn.extend({ 212 /** 213 * Setups the carousel. 214 * 215 * @method setup 216 * @return undefined 217 */ 218 setup: function() { 219 this.first = null; 220 this.last = null; 221 this.prevFirst = null; 222 this.prevLast = null; 223 this.animating = false; 224 this.timer = null; 225 this.resizeTimer = null; 226 this.tail = null; 227 this.inTail = false; 228 229 if (this.locked) { 230 return; 231 } 232 233 this.list.css(this.lt, this.pos(this.options.offset) + 'px'); 234 var p = this.pos(this.options.start, true); 235 this.prevFirst = this.prevLast = null; 236 this.animate(p, false); 237 238 $(window).unbind('resize.jcarousel', this.funcResize).bind('resize.jcarousel', this.funcResize); 239 240 if (this.options.setupCallback !== null) { 241 this.options.setupCallback(this); 242 } 243 }, 244 245 /** 246 * Clears the list and resets the carousel. 247 * 248 * @method reset 249 * @return undefined 250 */ 251 reset: function() { 252 this.list.empty(); 253 254 this.list.css(this.lt, '0px'); 255 this.list.css(this.wh, '10px'); 256 257 if (this.options.initCallback !== null) { 258 this.options.initCallback(this, 'reset'); 259 } 260 261 this.setup(); 262 }, 263 264 /** 265 * Reloads the carousel and adjusts positions. 266 * 267 * @method reload 268 * @return undefined 269 */ 270 reload: function() { 271 if (this.tail !== null && this.inTail) { 272 this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + this.tail); 273 } 274 275 this.tail = null; 276 this.inTail = false; 277 278 if (this.options.reloadCallback !== null) { 279 this.options.reloadCallback(this); 280 } 281 282 if (this.options.visible !== null) { 283 var self = this; 284 var di = Math.ceil(this.clipping() / this.options.visible), wh = 0, lt = 0; 285 this.list.children('li').each(function(i) { 286 wh += self.dimension(this, di); 287 if (i + 1 < self.first) { 288 lt = wh; 289 } 290 }); 291 292 this.list.css(this.wh, wh + 'px'); 293 this.list.css(this.lt, -lt + 'px'); 294 } 295 296 this.scroll(this.first, false); 297 }, 298 299 /** 300 * Locks the carousel. 301 * 302 * @method lock 303 * @return undefined 304 */ 305 lock: function() { 306 this.locked = true; 307 this.buttons(); 308 }, 309 310 /** 311 * Unlocks the carousel. 312 * 313 * @method unlock 314 * @return undefined 315 */ 316 unlock: function() { 317 this.locked = false;
318 this.buttons(); 319 }, 320 321 /** 322 * Sets the size of the carousel. 323 * 324 * @method size 325 * @return undefined 326 * @param s {Number} The size of the carousel. 327 */ 328 size: function(s) { 329 if (s !== undefined) { 330 this.options.size = s; 331 if (!this.locked) { 332 this.buttons(); 333 } 334 } 335 336 return this.options.size; 337 }, 338 339 /** 340 * Checks whether a list element exists for the given index (or index range). 341 * 342 * @method get 343 * @return bool 344 * @param i {Number} The index of the (first) element. 345 * @param i2 {Number} The index of the last element. 346 */ 347 has: function(i, i2) { 348 if (i2 === undefined || !i2) { 349 i2 = i; 350 } 351 352 if (this.options.size !== null && i2 > this.options.size) { 353 i2 = this.options.size; 354 } 355 356 for (var j = i; j <= i2; j++) { 357 var e = this.get(j); 358 if (!e.length || e.hasClass('jcarousel-item-placeholder')) { 359 return false; 360 } 361 } 362 363 return true; 364 }, 365 366 /** 367 * Returns a jQuery object with list element for the given index. 368 * 369 * @method get 370 * @return jQuery 371 * @param i {Number} The index of the element. 372 */ 373 get: function(i) { 374 return $('>.jcarousel-item-' + i, this.list); 375 }, 376 377 /** 378 * Adds an element for the given index to the list. 379 * If the element already exists, it updates the inner html. 380 * Returns the created element as jQuery object. 381 * 382 * @method add 383 * @return jQuery 384 * @param i {Number} The index of the element. 385 * @param s {String} The innerHTML of the element. 386 */ 387 add: function(i, s) { 388 var e = this.get(i), old = 0, n = $(s); 389 390 if (e.length === 0) { 391 var c, j = $jc.intval(i); 392 e = this.create(i); 393 while (true) { 394 c = this.get(--j); 395 if (j <= 0 || c.length) { 396 if (j <= 0) { 397 this.list.prepend(e); 398 } else { 399 c.after(e); 400 } 401 break; 402 } 403 } 404 } else { 405 old = this.dimension(e); 406 } 407 408 if (n.get(0).nodeName.toUpperCase() == 'LI') { 409 e.replaceWith(n); 410 e = n; 411 } else { 412 e.empty().append(s); 413 } 414 415 this.format(e.removeClass(this.className('jcarousel-item-placeholder')), i); 416 417 var di = this.options.visible !== null ? Math.ceil(this.clipping() / this.options.visible) : null; 418 var wh = this.dimension(e, di) - old; 419 420 if (i > 0 && i < this.first) { 421 this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - wh + 'px'); 422 } 423 424 this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) + wh + 'px'); 425 426 return e; 427 }, 428 429 /** 430 * Removes an element for the given index from the list. 431 * 432 * @method remove 433 * @return undefined 434 * @param i {Number} The index of the element. 435 */ 436 remove: function(i) { 437 var e = this.get(i); 438 439 // Check if item exists and is not currently visible 440 if (!e.length || (i >= this.first && i <= this.last)) { 441 return; 442 } 443 444 var d = this.dimension(e); 445 446 if (i < this.first) { 447 this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) + d + 'px'); 448 } 449 450 e.remove(); 451 452 this.list.css(this.wh, $jc.intval(this.list.css(this.wh)) - d + 'px'); 453 }, 454 455 /** 456 * Moves the carousel forwards. 457 * 458 * @method next 459 * @return undefined 460 */ 461 next: function() { 462 if (this.tail !== null && !this.inTail) { 463 this.scrollTail(false); 464 } else { 465 this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'last') && this.options.size !== null && this.last == this.options.size) ? 1 : this.first + this.options.scroll); 466 } 467 }, 468 469 /** 470 * Moves the carousel backwards. 471 * 472 * @method prev 473 * @return undefined 474 */ 475 prev: function() { 476 if (this.tail !== null && this.inTail) { 477 this.scrollTail(true); 478 } else { 479 this.scroll(((this.options.wrap == 'both' || this.options.wrap == 'first') && this.options.size !== null && this.first == 1) ? this.options.size : this.first - this.options.scroll); 480 } 481 }, 482 483 /** 484 * Scrolls the tail of the carousel. 485 * 486 * @method scrollTail 487 * @return undefined 488 * @param b {Boolean} Whether scroll the tail back or forward. 489 */ 490 scrollTail: function(b) { 491 if (this.locked || this.animating || !this.tail) { 492 return; 493 } 494 495 this.pauseAuto(); 496 497 var pos = $jc.intval(this.list.css(this.lt)); 498 499 pos = !b ? pos - this.tail : pos + this.tail; 500 this.inTail = !b; 501 502 // Save for callbacks 503 this.prevFirst = this.first; 504 this.prevLast = this.last; 505 506 this.animate(pos); 507 }, 508 509 /** 510 * Scrolls the carousel to a certain position. 511 * 512 * @method scroll 513 * @return undefined 514 * @param i {Number} The index of the element to scoll to. 515 * @param a {Boolean} Flag indicating whether to perform animation. 516 */ 517 scroll: function(i, a) { 518 if (this.locked || this.animating) { 519 return; 520 } 521 522 this.pauseAuto(); 523 this.animate(this.pos(i), a); 524 }, 525 526 /** 527 * Prepares the carousel and return the position for a certian index. 528 * 529 * @method pos 530 * @return {Number} 531 * @param i {Number} The index of the element to scoll to. 532 * @param fv {Boolean} Whether to force last item to be visible. 533 */ 534 pos: function(i, fv) { 535 var pos = $jc.intval(this.list.css(this.lt)); 536 537 if (this.locked || this.animating) { 538 return pos; 539 } 540 541 if (this.options.wrap != 'circular') { 542 i = i < 1 ? 1 : (this.options.size && i > this.options.size ? this.options.size : i); 543 } 544 545 var back = this.first > i; 546 547 // Create placeholders, new list width/height 548 // and new list position 549 var f = this.options.wrap != 'circular' && this.first <= 1 ? 1 : this.first; 550 var c = back ? this.get(f) : this.get(this.last); 551 var j = back ? f : f - 1; 552 var e = null, l = 0, p = false, d = 0, g; 553 554 while (back ? --j >= i : ++j < i) { 555 e = this.get(j); 556 p = !e.length; 557 if (e.length === 0) { 558 e = this.create(j).addClass(this.className('jcarousel-item-placeholder')); 559 c[back ? 'before' : 'after' ](e); 560 561 if (this.first !== null && this.options.wrap == 'circular' && this.options.size !== null && (j <= 0 || j > this.options.size)) { 562 g = this.get(this.index(j)); 563 if (g.length) { 564 e = this.add(j, g.clone(true)); 565 } 566 } 567 } 568 569 c = e; 570 d = this.dimension(e); 571 572 if (p) { 573 l += d; 574 } 575 576 if (this.first !== null && (this.options.wrap == 'circular' || (j >= 1 && (this.options.size === null || j <= this.options.size)))) { 577 pos = back ? pos + d : pos - d; 578 } 579 } 580 581 // Calculate visible items 582 var clipping = this.clipping(), cache = [], visible = 0, v = 0; 583 if (!clipping) { 584 return 585 } 586 c = this.get(i - 1); 587 j = i; 588 589 while (++visible) { 590 e = this.get(j); 591 p = !e.length; 592 if (e.length === 0) { 593 e = this.create(j).addClass(this.className('jcarousel-item-placeholder')); 594 // This should only happen on a next scroll 595 if (c.length === 0) { 596 this.list.prepend(e); 597 } else { 598 c[back ? 'before' : 'after' ](e); 599 } 600 601 if (this.first !== null && this.options.wrap == 'circular' && this.options.size !== null && (j <= 0 || j > this.options.size)) { 602 g = this.get(this.index(j)); 603 if (g.length) { 604 e = this.add(j, g.clone(true)); 605 } 606 } 607 } 608 609 c = e; 610 d = this.dimension(e); 611 if (d === 0) { 612 throw new Error('jCarousel: No width/height set for items. This will cause an infinite loop. Aborting...'); 613 } 614 615 if (this.options.wrap != 'circular' && this.options.size !== null && j > this.options.size) { 616 cache.push(e); 617 } else if (p) { 618 l += d; 619 } 620 621 v += d; 622 623 if (v >= clipping) { 624 break; 625 } 626 627 j++; 628 } 629 630 // Remove out-of-range placeholders 631 for (var x = 0; x < cache.length; x++) { 632 cache[x].remove(); 633 } 634 635 // Resize list 636 if (l > 0) { 637 this.list.css(this.wh, this.dimension(this.list) + l + 'px'); 638 639 if (back) { 640 pos -= l; 641 this.list.css(this.lt, $jc.intval(this.list.css(this.lt)) - l + 'px'); 642 } 643 } 644 645 // Calculate first and last item 646 var last = i + visible - 1; 647 if (this.options.wrap != 'circular' && this.options.size && last > this.options.size) { 648 last = this.options.size; 649 } 650 651 if (j > last) { 652 visible = 0; 653 j = last; 654 v = 0; 655 while (++visible) { 656 e = this.get(j--); 657 if (!e.length) { 658 break; 659 } 660 v += this.dimension(e); 661 if (v >= clipping) { 662 break; 663 } 664 } 665 } 666 667 var first = last - visible + 1; 668 if (this.options.wrap != 'circular' && first < 1) { 669 first = 1; 670 } 671 672 if (this.inTail && back) { 673 pos += this.tail; 674 this.inTail = false;
675 } 676 677 this.tail = null; 678 if (this.options.wrap != 'circular' && last == this.options.size && (last - visible + 1) >= 1) { 679 var m = $jc.intval(this.get(last).css(!this.options.vertical ? 'marginRight' : 'marginBottom')); 680 if ((v - m) > clipping) { 681 this.tail = v - clipping - m; 682 } 683 } 684 685 if (fv && i === this.options.size && this.tail) { 686 pos -= this.tail; 687 this.inTail = true; 688 } 689 690 // Adjust position 691 while (i-- > first) { 692 pos += this.dimension(this.get(i)); 693 } 694 695 // Save visible item range 696 this.prevFirst = this.first; 697 this.prevLast = this.last; 698 this.first = first; 699 this.last = last; 700 701 return pos; 702 }, 703 704 /** 705 * Animates the carousel to a certain position. 706 * 707 * @method animate 708 * @return undefined 709 * @param p {Number} Position to scroll to. 710 * @param a {Boolean} Flag indicating whether to perform animation. 711 */ 712 animate: function(p, a) { 713 if (this.locked || this.animating) { 714 return; 715 } 716 717 this.animating = true; 718 719 var self = this; 720 var scrolled = function() { 721 self.animating = false; 722 723 if (p === 0) { 724 self.list.css(self.lt, 0); 725 } 726 727 if (!self.autoStopped && (self.options.wrap == 'circular' || self.options.wrap == 'both' || self.options.wrap == 'last' || self.options.size === null || self.last < self.options.size || (self.last == self.options.size && self.tail !== null && !self.inTail))) { 728 self.startAuto(); 729 } 730 731 self.buttons(); 732 self.notify('onAfterAnimation'); 733 734 // This function removes items which are appended automatically for circulation. 735 // This prevents the list from growing infinitely. 736 if (self.options.wrap == 'circular' && self.options.size !== null) { 737 for (var i = self.prevFirst; i <= self.prevLast; i++) { 738 if (i !== null && !(i >= self.first && i <= self.last) && (i < 1 || i > self.options.size)) { 739 self.remove(i); 740 } 741 } 742 } 743 }; 744 745 this.notify('onBeforeAnimation'); 746 747 // Animate 748 if (!this.options.animation || a === false) { 749 this.list.css(this.lt, p + 'px'); 750 scrolled(); 751 } else { 752 var o = !this.options.vertical ? (this.options.rtl ? {'right': p} : {'left': p}) : {'top': p}; 753 // Define animation settings. 754 var settings = { 755 duration: this.options.animation, 756 easing: this.options.easing, 757 complete: scrolled 758 }; 759 // If we have a step callback, specify it as well. 760 if ($.isFunction(this.options.animationStepCallback)) { 761 settings.step = this.options.animationStepCallback; 762 } 763 // Start the animation. 764 this.list.animate(o, settings); 765 } 766 }, 767 768 /** 769 * Starts autoscrolling. 770 * 771 * @method auto 772 * @return undefined 773 * @param s {Number} Seconds to periodically autoscroll the content. 774 */ 775 startAuto: function(s) { 776 if (s !== undefined) { 777 this.options.auto = s; 778 } 779 780 if (this.options.auto === 0) { 781 return this.stopAuto(); 782 } 783 784 if (this.timer !== null) { 785 return; 786 } 787 788 this.autoStopped = false; 789 790 var self = this; 791 this.timer = window.setTimeout(function() { self.next(); }, this.options.auto * 1000); 792 }, 793 794 /** 795 * Stops autoscrolling. 796 * 797 * @method stopAuto 798 * @return undefined 799 */ 800 stopAuto: function() { 801 this.pauseAuto(); 802 this.autoStopped = true; 803 }, 804 805 /** 806 * Pauses autoscrolling. 807 * 808 * @method pauseAuto 809 * @return undefined 810 */ 811 pauseAuto: function() { 812 if (this.timer === null) { 813 return; 814 } 815 816 window.clearTimeout(this.timer); 817 this.timer = null; 818 }, 819 820 /** 821 * Sets the states of the prev/next buttons. 822 * 823 * @method buttons 824 * @return undefined 825 */ 826 buttons: function(n, p) { 827 if (n == null) { 828 n = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'first') || this.options.size === null || this.last < this.options.size); 829 if (!this.locked && (!this.options.wrap || this.options.wrap == 'first') && this.options.size !== null && this.last >= this.options.size) { 830 n = this.tail !== null && !this.inTail; 831 } 832 } 833 834 if (p == null) { 835 p = !this.locked && this.options.size !== 0 && ((this.options.wrap && this.options.wrap != 'last') || this.first > 1); 836 if (!this.locked && (!this.options.wrap || this.options.wrap == 'last') && this.options.size !== null && this.first == 1) { 837 p = this.tail !== null && this.inTail; 838 } 839 } 840 841 var self = this; 842 843 if (this.buttonNext.size() > 0) { 844 this.buttonNext.unbind(this.options.buttonNextEvent + '.jcarousel', this.funcNext); 845 846 if (n) { 847 this.buttonNext.bind(this.options.buttonNextEvent + '.jcarousel', this.funcNext); 848 } 849 850 this.buttonNext[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled', n ? false : true); 851 852 if (this.options.buttonNextCallback !== null && this.buttonNext.data('jcarou
852selstate') != n) { 853 this.buttonNext.each(function() { self.options.buttonNextCallback(self, this, n); }).data('jcarouselstate', n); 854 } 855 } else { 856 if (this.options.buttonNextCallback !== null && this.buttonNextState != n) { 857 this.options.buttonNextCallback(self, null, n); 858 } 859 } 860 861 if (this.buttonPrev.size() > 0) { 862 this.buttonPrev.unbind(this.options.buttonPrevEvent + '.jcarousel', this.funcPrev); 863 864 if (p) { 865 this.buttonPrev.bind(this.options.buttonPrevEvent + '.jcarousel', this.funcPrev); 866 } 867 868 this.buttonPrev[p ? 'removeClass' : 'addClass'](this.className('jcarousel-prev-disabled')).attr('disabled', p ? false : true); 869 870 if (this.options.buttonPrevCallback !== null && this.buttonPrev.data('jcarouselstate') != p) { 871 this.buttonPrev.each(function() { self.options.buttonPrevCallback(self, this, p); }).data('jcarouselstate', p); 872 } 873 } else { 874 if (this.options.buttonPrevCallback !== null && this.buttonPrevState != p) { 875 this.options.buttonPrevCallback(self, null, p); 876 } 877 } 878 879 this.buttonNextState = n; 880 this.buttonPrevState = p; 881 }, 882 883 /** 884 * Notify callback of a specified event. 885 * 886 * @method notify 887 * @return undefined 888 * @param evt {String} The event name 889 */ 890 notify: function(evt) { 891 var state = this.prevFirst === null ? 'init' : (this.prevFirst < this.first ? 'next' : 'prev'); 892 893 // Load items 894 this.callback('itemLoadCallback', evt, state); 895 896 if (this.prevFirst !== this.first) { 897 this.callback('itemFirstInCallback', evt, state, this.first); 898 this.callback('itemFirstOutCallback', evt, state, this.prevFirst); 899 } 900 901 if (this.prevLast !== this.last) { 902 this.callback('itemLastInCallback', evt, state, this.last); 903 this.callback('itemLastOutCallback', evt, state, this.prevLast); 904 } 905 906 this.callback('itemVisibleInCallback', evt, state, this.first, this.last, this.prevFirst, this.prevLast); 907 this.callback('itemVisibleOutCallback', evt, state, this.prevFirst, this.prevLast, this.first, this.last); 908 }, 909 910 callback: function(cb, evt, state, i1, i2, i3, i4) { 911 if (this.options[cb] == null || (typeof this.options[cb] != 'object' && evt != 'onAfterAnimation')) { 912 return; 913 } 914 915 var callback = typeof this.options[cb] == 'object' ? this.options[cb][evt] : this.options[cb]; 916 917 if (!$.isFunction(callback)) { 918 return; 919 } 920 921 var self = this; 922 923 if (i1 === undefined) { 924 callback(self, state, evt); 925 } else if (i2 === undefined) { 926 this.get(i1).each(function() { callback(self, this, i1, state, evt); }); 927 } else { 928 var call = function(i) { 929 self.get(i).each(function() { callback(self, this, i, state, evt); }); 930 }; 931 for (var i = i1; i <= i2; i++) { 932 if (i !== null && !(i >= i3 && i <= i4)) { 933 call(i); 934 } 935 } 936 } 937 }, 938 939 create: function(i) { 940 return this.format('<li></li>', i); 941 }, 942 943 format: function(e, i) { 944 e = $(e); 945 var split = e.get(0).className.split(' '); 946 for (var j = 0; j < split.length; j++) { 947 if (split[j].indexOf('jcarousel-') != -1) { 948 e.removeClass(split[j]); 949 } 950 } 951 e.addClass(this.className('jcarousel-item')).addClass(this.className('jcarousel-item-' + i)).css({ 952 'float': (this.options.rtl ? 'right' : 'left'), 953 'list-style': 'none' 954 }).attr('jcarouselindex', i); 955 return e; 956 }, 957 958 className: function(c) { 959 return c + ' ' + c + (!this.options.vertical ? '-horizontal' : '-vertical'); 960 }, 961 962 dimension: function(e, d) { 963 var el = $(e); 964 965 if (d == null) { 966 return !this.options.vertical ? 967 ((el.innerWidth() + 968 $jc.intval(el.css('margin-left')) + 969 $jc.intval(el.css('margin-right')) + 970 $jc.intval(el.css('border-left-width')) + 971 $jc.intval(el.css('border-right-width'))) || $jc.intval(this.options.itemFallbackDimension)) :
972 ((el.innerHeight() + 973 $jc.intval(el.css('margin-top')) + 974 $jc.intval(el.css('margin-bottom')) + 975 $jc.intval(el.css('border-top-width')) + 976 $jc.intval(el.css('border-bottom-width'))) || $jc.intval(this.options.itemFallbackDimension)); 977 } else { 978 var w = !this.options.vertical ? 979 d - $jc.intval(el.css('marginLeft')) - $jc.intval(el.css('marginRight')) : 980 d - $jc.intval(el.css('marginTop')) - $jc.intval(el.css('marginBottom')); 981 982 $(el).css(this.wh, w + 'px'); 983 984 return this.dimension(el); 985 } 986 }, 987 988 clipping: function() { 989 if (!this.clip || this.clip.length == 0) { 990 return 0 991 } 992 console.log('debugging: ', this.clip); 993 if (!this.clip[0]) return 0; 994 return !this.options.vertical ? 995 this.clip[0].offsetWidth - $jc.intval(this.clip.css('borderLeftWidth')) - $jc.intval(this.clip.css('borderRightWidth')) : 996 this.clip[0].offsetHeight - $jc.intval(this.clip.css('borderTopWidth')) - $jc.intval(this.clip.css('borderBottomWidth')); 997 }, 998 999 index: function(i, s) { 1000 if (s == null) { 1001 s = this.options.size; 1002 } 1003 1004 return Math.round((((i-1) / s) - Math.floor((i-1) / s)) * s) + 1; 1005 } 1006 }); 1007 1008 $jc.extend({ 1009 /** 1010 * Gets/Sets the global default configuration properties. 1011 * 1012 * @method defaults 1013 * @return {Object} 1014 * @param d {Object} A set of key/value pairs to set as configuration properties. 1015 */ 1016 defaults: function(d) { 1017 return $.extend(defaults, d || {}); 1018 }, 1019 1020 intval: function(v) { 1021 v = parseInt(v, 10); 1022 return isNaN(v) ? 0 : v; 1023 }, 1024 1025 windowLoaded: function() { 1026 windowLoaded = true; 1027 }, 1028 1029 isSafari: function() { 1030 var ua = navigator.userAgent.toLowerCase(), 1031 match = /(chrome)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+)/.exec(ua) || [], 1032 browser = match[1] || ""; 1033 1034 return browser === 'webkit'; 1035 } 1036 }); 1037 1038 /** 1039 * Creates a carousel for all matched elements. 1040 * 1041 * @example $("#mycarousel").jcarousel(); 1042 * @before <ul id="mycarousel" class="jcarousel-skin-name"><li>First item</li><li>Second item</li></ul> 1043 * @result 1044 * 1045 * <div class="jcarousel-skin-name"> 1046 * <div class="jcarousel-container"> 1047 * <div class="jcarousel-clip"> 1048 * <ul class="jcarousel-list"> 1049 * <li class="jcarousel-item-1">First item</li> 1050 * <li class="jcarousel-item-2">Second item</li> 1051 * </ul> 1052 * </div> 1053 * <div disabled="disabled" class="jcarousel-prev jcarousel-prev-disabled"></div> 1054 * <div class="jcarousel-next"></div> 1055 * </div> 1056 * </div> 1057 * 1058 * @method jcarousel 1059 * @return jQuery 1060 * @param o {Hash|String} A set of key/value pairs to set as configuration properties or a method name to call on a formerly created instance. 1061 */ 1062 $.fn.jcarousel = function(o) { 1063 if (typeof o == 'string') { 1064 var instance = $(this).data('jcarousel'), args = Array.prototype.slice.call(arguments, 1); 1065 return instance[o].apply(instance, args); 1066 } else { 1067 return this.each(function() { 1068 var instance = $(this).data('jcarousel'); 1069 if (instance) { 1070 if (o) { 1071 $.extend(instance.options, o); 1072 } 1073 instance.reload(); 1074 } else { 1075 $(this).data('jcarousel', new $jc(this, o)); 1076 } 1077 }); 1078 } 1079 }; 1080 1081})(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.