1/** 2 * jquery.elastislide.js v1.1.0 3 * http://www.codrops.com 4 * 5 * Licensed under the MIT license. 6 * http://www.opensource.org/licenses/mit-license.php 7 * 8 * Copyright 2012, Codrops 9 * http://www.codrops.com 10 */ 11 12;( function( $, window, undefined ) { 13 14 'use strict'; 15 16 /* 17 * debouncedresize: special jQuery event that happens once after a window resize 18 * 19 * latest version and complete README available on Github: 20 * https://github.com/louisremi/jquery-smartresize/blob/master/jquery.debouncedresize.js 21 * 22 * Copyright 2011 @louis_remi 23 * Licensed under the MIT license. 24 */ 25 var $event = $.event, 26 $special, 27 resizeTimeout; 28 29 $special = $event.special.debouncedresize = { 30 setup: function() { 31 $( this ).on( "resize", $special.handler ); 32 }, 33 teardown: function() { 34 $( this ).off( "resize", $special.handler ); 35 }, 36 handler: function( event, execAsap ) { 37 // Save the context 38 var context = this, 39 args = arguments, 40 dispatch = function() { 41 // set correct event type 42 event.type = "debouncedresize"; 43 $event.dispatch.apply( context, args ); 44 }; 45 46 if ( resizeTimeout ) { 47 clearTimeout( resizeTimeout ); 48 } 49 50 execAsap ? 51 dispatch() : 52 resizeTimeout = setTimeout( dispatch, $special.threshold ); 53 }, 54 threshold: 150 55 }; 56 57 // ======================= imagesLoaded Plugin =============================== 58 // https://github.com/desandro/imagesloaded 59 60 // $('#my-container').imagesLoaded(myFunction) 61 // execute a callback when all images have loaded. 62 // needed because .load() doesn't work on cached images 63 64 // callback function gets image collection as argument 65 // this is the container 66 67 // original: mit license. paul irish. 2010. 68 // contributors: Oren Solomianik, David DeSandro, Yiannis Chatzikonstantinou 69 70 // blank image data-uri bypasses webkit log warning (thx doug jones) 71 var BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='; 72 73 $.fn.imagesLoaded = function( callback ) { 74 var $this = this, 75 deferred = $.isFunction($.Deferred) ? $.Deferred() : 0, 76 hasNotify = $.isFunction(deferred.notify), 77 $images = $this.find('img').add( $this.filter('img') ), 78 loaded = [], 79 proper = [], 80 broken = []; 81 82 // Register deferred callbacks 83 if ($.isPlainObject(callback)) { 84 $.each(callback, function (key, value) { 85 if (key === 'callback') { 86 callback = value; 87 } else if (deferred) { 88 deferred[key](value); 89 } 90 }); 91 } 92 93 function doneLoading() { 94 var $proper = $(proper), 95 $broken = $(broken); 96 97 if ( deferred ) { 98 if ( broken.length ) { 99 deferred.reject( $images, $proper, $broken ); 100 } else { 101 deferred.resolve( $images ); 102 } 103 } 104 105 if ( $.isFunction( callback ) ) { 106 callback.call( $this, $images, $proper, $broken ); 107 } 108 } 109 110 function imgLoaded( img, isBroken ) { 111 // don't proceed if BLANK image, or image is already loaded 112 if ( img.src === BLANK || $.inArray( img, loaded ) !== -1 ) { 113 return; 114 } 115 116 // store element in loaded images array 117 loaded.push( img ); 118 119 // keep track of broken and properly loaded images 120 if ( isBroken ) { 121 broken.push( img ); 122 } else { 123 proper.push( img ); 124 } 125 126 // cache image and its state for future calls 127 $.data( img, 'imagesLoaded', { isBroken: isBroken, src: img.src } ); 128 129 // trigger deferred progress method if present 130 if ( hasNotify ) { 131 deferred.notifyWith( $(img), [ isBroken, $images, $(proper), $(broken) ] ); 132 } 133 134 // call doneLoading and clean listeners if all images are loaded 135 if ( $images.length === loaded.length ){ 136 setTimeout( doneLoading ); 137 $images.unbind( '.imagesLoaded' ); 138 } 139 } 140 141 // if no images, trigger immediately 142 if ( !$images.length ) { 143 doneLoading(); 144 } else { 145 $images.bind( 'load.imagesLoaded error.imagesLoaded', function( event ){ 146 // trigger imgLoaded 147 imgLoaded( event.target, event.type === 'error' ); 148 }).each( function( i, el ) { 149 var src = el.src; 150 151 // find out if this image has been already checked for status 152 // if it was, and src has not changed, call imgLoaded on it 153 var cached = $.data( el, 'imagesLoaded' ); 154 if ( cached && cached.src === src ) { 155 imgLoaded( el, cached.isBroken ); 156 return; 157 } 158 159 // if complete is true and browser supports natural sizes, try 160 // to check for image status manually
161 if ( el.complete && el.naturalWidth !== undefined ) { 162 imgLoaded( el, el.naturalWidth === 0 || el.naturalHeight === 0 ); 163 return; 164 } 165 166 // cached images don't fire load sometimes, so we reset src, but only when 167 // dealing with IE, or image is complete (loaded) and failed manual check 168 // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f 169 if ( el.readyState || el.complete ) { 170 el.src = BLANK; 171 el.src = src; 172 } 173 }); 174 } 175 176 return deferred ? deferred.promise( $this ) : $this; 177 }; 178 179 // global 180 var $window = $( window ), 181 Modernizr = window.Modernizr; 182 183 $.Elastislide = function( options, element ) { 184 185 this.$el = $( element ); 186 this._init( options ); 187 188 }; 189 190 $.Elastislide.defaults = { 191 // orientation 'horizontal' || 'vertical' 192 orientation : 'horizontal', 193 // sliding speed 194 speed : 500, 195 // sliding easing 196 easing : 'ease-in-out', 197 // the minimum number of items to show. 198 // when we resize the window, this will make sure minItems are always shown 199 // (unless of course minItems is higher than the total number of elements) 200 minItems : 3, 201 // index of the current item (left most item of the carousel) 202 start : 0, 203 // click item callback 204 onClick : function( el, position, evt ) { return false; }, 205 onReady : function() { return false; }, 206 onBeforeSlide : function() { return false; }, 207 onAfterSlide : function() { return false; } 208 }; 209 210 $.Elastislide.prototype = { 211 212 _init : function( options ) { 213 214 // options 215 this.options = $.extend( true, {}, $.Elastislide.defaults, options ); 216 217 // https://github.com/twitter/bootstrap/issues/2870 218 var self = this, 219 transEndEventNames = { 220 'WebkitTransition' : 'webkitTransitionEnd', 221 'MozTransition' : 'transitionend', 222 'OTransition' : 'oTransitionEnd', 223 'msTransition' : 'MSTransitionEnd', 224 'transition' : 'transitionend' 225 }; 226 227 this.transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ]; 228 229 // suport for css transforms and css transitions 230 this.support = Modernizr.csstransitions && Modernizr.csstransforms;
231 232 // current item's index 233 this.current = this.options.start; 234 235 // control if it's sliding 236 this.isSliding = false; 237 238 this.$items = this.$el.children( 'li' ); 239 // total number of items 240 this.itemsCount = this.$items.length; 241 if( this.itemsCount === 0 ) { 242 243 return false; 244 245 } 246 this._validate(); 247 // remove white space 248 this.$items.detach(); 249 this.$el.empty(); 250 this.$el.append( this.$items ); 251 252 // main wrapper 253 this.$el.wrap( '<div class="elastislide-wrapper elastislide-loading elastislide-' + this.options.orientation + '"></div>' ); 254 255 // check if we applied a transition to the <ul> 256 this.hasTransition = false; 257 258 // add transition for the <ul> 259 this.hasTransitionTimeout = setTimeout( function() { 260 261 self._addTransition(); 262 263 }, 100 ); 264 265 // preload the images 266 267 this.$el.imagesLoaded( function() { 268 269 self.$el.show(); 270 271 self._layout(); 272 self._configure(); 273 274 if( self.hasTransition ) { 275 276 // slide to current's position 277 self._removeTransition(); 278 self._slideToItem( self.current ); 279 280 self.$el.on( self.transEndEventName, function() { 281 282 self.$el.off( self.transEndEventName ); 283 self._setWrapperSize(); 284 // add transition for the <ul> 285 self._addTransition(); 286 self._initEvents(); 287 288 } ); 289 290 } 291 else { 292 293 clearTimeout( self.hasTransitionTimeout ); 294 self._setWrapperSize(); 295 self._initEvents(); 296 // slide to current's position 297 self._slideToItem( self.current ); 298 setTimeout( function() { self._addTransition(); }, 25 ); 299 300 } 301 302 self.options.onReady(); 303 304 } ); 305 306 }, 307 _validate : function() { 308 309 if( this.options.speed < 0 ) { 310 311 this.options.speed = 500; 312 313 } 314 if( this.options.minItems < 1 || this.options.minItems > this.itemsCount ) { 315 316 this.options.minItems = 1; 317 318 } 319 if( this.options.start < 0 || this.options.start > this.itemsCount - 1 ) { 320 321 this.options.start = 0; 322 323 } 324 if( this.options.orientation != 'horizontal' && this.options.orientation != 'vertical' ) { 325 326 this.options.orientation = 'horizontal'; 327 328 } 329 330 }, 331 _layout : function() { 332 333 this.$el.wrap( '<div class="elastislide-carousel"></div>' ); 334 335 this.$carousel = this.$el.parent(); 336 this.$wrapper = this.$carousel.parent().removeClass( 'elastislide-loading' ); 337 338 // save original image sizes 339 var $img = this.$items.find( 'img:first' ); 340 this.imgSize = { width : $img.outerWidth( true ), height : $img.outerHeight( true ) }; 341 342 this._setItemsSize(); 343 this.options.orientation === 'horizontal' ? this.$el.css( 'max-height', this.imgSize.height ) : this.$el.css( 'height', this.options.minItems * this.imgSize.height ); 344 345 // add the controls 346 this._addControls(); 347 348 }, 349 _addTransition : function() { 350 351 if( this.support ) { 352 353 this.$el.css( 'transition', 'all ' + this.options.speed + 'ms ' + this.options.easing ); 354 355 } 356 this.hasTransition = true; 357 358 }, 359 _removeTransition : function() { 360 361 if( this.support ) { 362 363 this.$el.css( 'transition', 'all 0s' ); 364 365 } 366 this.hasTransition = false; 367 368 }, 369 _addControls : function() { 370 371 var self = this; 372 373 // add navigation elements 374 this.$navigation = $( '<nav><span class="elastislide-prev">Previous</span><span class="elastislide-next">Next</span></nav>' ) 375 .appendTo( this.$wrapper ); 376 377 378 this.$navPrev = this.$navigation.find( 'span.elastislide-prev' ).on( 'mousedown.elastislide', function( event ) { 379 380 self._slide( 'prev' ); 381 return false; 382 383 } ); 384 385 this.$navNext = this.$navigation.find( 'span.elastislide-next' ).on( 'mousedown.elastislide', function( event ) { 386 387 self._slide( 'next' ); 388 return false; 389 390 } ); 391 392 }, 393 _setItemsSize : function() { 394 395 // width for the items (%) 396 var w = this.options.orientation === 'horizontal' ? ( Math.floor( this.$carousel.width() / this.options.minItems ) * 100 ) / this.$carousel.width() : 100; 397 398 this.$items.css( { 399 'width' : w + '%', 400 'max-width' : this.imgSize.width, 401 'max-height' : this.imgSize.height 402 } ); 403 404 if( this.options.orientation === 'vertical' ) { 405 406 this.$wrapper.css( 'max-width', this.imgSize.width + parseInt( this.$wrapper.css( 'padding-left' ) ) + parseInt( this.$wrapper.css( 'padding-right' ) ) ); 407 408 } 409 410 }, 411 _setWrapperSize : function() { 412 413 if( this.options.orientation === 'vertical' ) { 414 415 this.$wrapper.css( { 416 'height' : this.options.minItems * this.imgSize.height + parseInt( this.$wrapper.css( 'padding-top' ) ) + parseInt( this.$wrapper.css( 'padding-bottom' ) ) 417 } ); 418 419 } 420 421 }, 422 _configure : function() { 423 424 // check how many items fit in the carousel (visible area -> this.$carousel.width() ) 425 this.fitCount = this.options.orientation === 'horizontal' ? 426 this.$carousel.width() < this.options.minItems * this.imgSize.width ? this.options.minItems : Math.floor( this.$carousel.width() / this.imgSize.width ) : 427 this.$carousel.height() < this.options.minItems * this.imgSize.height ? this.options.minItems : Math.floor( this.$carousel.height() / this.imgSize.height ); 428 429 }, 430 _initEvents : function() { 431 432 var self = this; 433 434 //if(this.options.autoplay == true){ 435 var translation = 0; 436 // width/height of an item ( <li> ) 437 var itemSpace = this.options.orientation === 'horizontal' ? this.$items.outerWidth( true ) : this.$items.outerHeight( true ); 438 // total width/height of the <ul> 439 var totalSpace = this.itemsCount * itemSpace; 440 // visible width/height 441 var visibleSpace = this.options.orientation === 'horizontal' ? this.$carousel.width() : this.$carousel.height(); 442 //slide auto 443 window.setInterval(function(){ 444 //test if we should go to next slide or return to first slide 445 if(totalSpace > translation + visibleSpace) 446 { 447 //go to next slide 448 self._slide('next'); 449 //update translation 450 translation += visibleSpace; 451 } 452 else 453 { 454 //return to first slide 455 self._slideTo(0); 456 //set translation to 0 457 translation = 0; 458 } 459 }, 7000); 460 //} 461 462 463 $window.on( 'debouncedresize.elastislide', function() { 464 465 self._setItemsSize(); 466 self._configure(); 467 self._slideToItem( self.current ); 468 469 } ); 470 471 this.$el.on( this.transEndEventName, function() { 472 473 self._onEndTransition(); 474 475 } ); 476 477 if( this.options.orientation === 'horizontal' ) { 478 479 this.$el.on( { 480 swipeleft : function() { 481 482 self._slide( 'next' ); 483 484 }, 485 swiperight : function() { 486 487 self._slide( 'prev' ); 488 489 } 490 } ); 491 492 } 493 else { 494 495 this.$el.on( { 496 swipeup : function() { 497 498 self._slide( 'next' ); 499 500 }, 501 swipedown : function() { 502 503 self._slide( 'prev' ); 504 505 } 506 } ); 507 508 } 509 510 // item click event 511 this.$el.on( 'click.elastislide', 'li', function( event ) { 512 513 var $item = $( this ); 514 515 self.options.onClick( $item, $item.index(), event ); 516 517 }); 518 519 }, 520 _destroy : function( callback ) { 521 522 this.$el.off( this.transEndEventName ).off( 'swipeleft swiperight swipeup swipedown .elastislide' ); 523 $window.off( '.elastislide' ); 524 525 this.$el.css( { 526 'max-height' : 'none', 527 'transition' : 'none' 528 } ).unwrap( this.$carousel ).unwrap( this.$wrapper ); 529 530 this.$items.css( { 531 'width' : 'auto', 532 'max-width' : 'none', 533 'max-height' : 'none' 534 } ); 535 536 this.$navigation.remove(); 537 this.$wrapper.remove(); 538 539 if( callback ) { 540 541 callback.call(); 542 543 } 544 545 }, 546 _toggleControls : function( dir, display ) { 547
548 if( display ) { 549 550 ( dir === 'next' ) ? this.$navNext.show() : this.$navPrev.show(); 551 552 } 553 else { 554 555 ( dir === 'next' ) ? this.$navNext.hide() : this.$navPrev.hide(); 556 557 } 558 559 }, 560 _slide : function( dir, tvalue ) { 561 562 if( this.isSliding ) { 563 564 return false; 565 566 } 567 568 this.options.onBeforeSlide(); 569 570 this.isSliding = true; 571 572 var self = this, 573 translation = this.translation || 0, 574 // width/height of an item ( <li> ) 575 itemSpace = this.options.orientation === 'horizontal' ? this.$items.outerWidth( true ) : this.$items.outerHeight( true ), 576 // total width/height of the <ul> 577 totalSpace = this.itemsCount * itemSpace, 578 // visible width/height 579 visibleSpace = this.options.orientation === 'horizontal' ? this.$carousel.width() : this.$carousel.height(); 580 581 if( tvalue === undefined ) { 582 583 var amount = this.fitCount * itemSpace; 584 585 if( amount < 0 ) { 586 587 return false; 588 589 } 590 591 if( dir === 'next' && totalSpace - ( Math.abs( translation ) + amount ) < visibleSpace ) { 592 593 amount = totalSpace - ( Math.abs( translation ) + visibleSpace ); 594 595 // show / hide navigation buttons 596 this._toggleControls( 'next', false ); 597 this._toggleControls( 'prev', true ); 598 599 } 600 else if( dir === 'prev' && Math.abs( translation ) - amount < 0 ) { 601 602 amount = Math.abs( translation ); 603 604 // show / hide navigation buttons 605 this._toggleControls( 'next', true ); 606 this._toggleControls( 'prev', false ); 607 608 } 609 else { 610 611 // future translation value 612 var ftv = dir === 'next' ? Math.abs( translation ) + Math.abs( amount ) : Math.abs( translation ) - Math.abs( amount ); 613 614 // show / hide navigation buttons 615 ftv > 0 ? this._toggleControls( 'prev', true ) : this._toggleControls( 'prev', false ); 616 ftv < totalSpace - visibleSpace ? this._toggleControls( 'next', true ) : this._toggleControls( 'next', false ); 617 618 } 619 620 tvalue = dir === 'next' ? translation - amount : translation + amount; 621 622 } 623 else { 624 625 var amount = Math.abs( tvalue ); 626 627 if( Math.max( totalSpace, visibleSpace ) - amount < visibleSpace ) { 628 629 tvalue = - ( Math.max( totalSpace, visibleSpace ) - visibleSpace ); 630 631 } 632 633 // show / hide navigation buttons 634 amount > 0 ? this._toggleControls( 'prev', true ) : this._toggleControls( 'prev', false ); 635 Math.max( totalSpace, visibleSpace ) - visibleSpace > amount ? this._toggleControls( 'next', true ) : this._toggleControls( 'next', false ); 636 637 } 638 639 this.translation = tvalue; 640 641 if( translation === tvalue ) { 642 643 this._onEndTransition(); 644 return false; 645 646 } 647 648 if( this.support ) { 649 650 this.options.orientation === 'horizontal' ? this.$el.css( 'transform', 'translateX(' + tvalue + 'px)' ) : this.$el.css( 'transform', 'translateY(' + tvalue + 'px)' ); 651 652 } 653 else { 654 655 $.fn.applyStyle = this.hasTransition ? $.fn.animate : $.fn.css; 656 var styleCSS = this.options.orientation === 'horizontal' ? { left : tvalue } : { top : tvalue }; 657 658 this.$el.stop().applyStyle( styleCSS, $.extend( true, [], { duration : this.options.speed, complete : function() { 659 660 self._onEndTransition(); 661 662 } } ) ); 663 664 } 665 666 if( !this.hasTransition ) { 667 668 this._onEndTransition(); 669 670 } 671 672 }, 673 _onEndTransition : function() { 674 675 this.isSliding = false; 676 this.options.onAfterSlide(); 677 678 }, 679 _slideTo : function( pos ) { 680 681 var pos = pos || this.current, 682 translation = Math.abs( this.translation ) || 0, 683 itemSpace = this.options.orientation === 'horizontal' ? this.$items.outerWidth( true ) : this.$items.outerHeight( true ), 684 posR = translation + this.$carousel.width(), 685 ftv = Math.abs( pos * itemSpace ); 686 687 if( ftv + itemSpace > posR || ftv < translation ) { 688 689 this._slideToItem( pos ); 690 691 } 692 693 }, 694 _slideToItem : function( pos ) { 695 696 // how much to slide? 697 var amount = this.options.orientation === 'horizontal' ? pos * this.$items.outerWidth( true ) : pos * this.$items.outerHeight( true ); 698 this._slide( '', -amount ); 699 700 }, 701 // public method: adds new items to the carousel 702 /* 703 704 how to use: 705 var carouselEl = $( '#carousel' ), 706 carousel = carouselEl.elastislide(); 707 ... 708 709 // append or prepend new items: 710 carouselEl.prepend('<li><a href="#"><img src="images/large/2.jpg" alt="image02" /></a></li>'); 711 712 // call the add method: 713 es.add(); 714 715 */ 716 add : function( callback ) { 717 718 var self = this, 719 oldcurrent = this.current, 720 $currentItem = this.$items.eq( this.current ); 721 722 // adds new items to the carousel 723 this.$items = this.$el.children( 'li' ); 724 this.itemsCount = this.$items.length; 725 this.current = $currentItem.index(); 726 this._setItemsSize(); 727 this._configure(); 728 this._removeTransition(); 729 oldcurrent < this.current ? this._slideToItem( this.current ) : this._slide( 'next', this.translation ); 730 setTimeout( function() { self._addTransition(); }, 25 ); 731 732 if ( callback ) { 733 734 callback.call(); 735 736 } 737 738 }, 739 // public method: sets a new element as the current. slides to that position 740 setCurrent : function( idx, callback ) { 741 742 this.current = idx; 743 744 this._slideTo(); 745 746 if ( callback ) { 747 748 callback.call(); 749 750 } 751 752 }, 753 // public method: slides to the next set of items 754 next : function() { 755 756 self._slide( 'next' ); 757 758 }, 759 // public method: slides to the previous set of items 760 previous : function() { 761 762 self._slide( 'prev' ); 763 764 }, 765 // public method: slides to the first item 766 slideStart : function() { 767 768 this._slideTo( 0 ); 769 770 }, 771 // public method: slides to the last item 772 slideEnd : function() { 773 774 this._slideTo( this.itemsCount - 1 ); 775 776 }, 777 // public method: destroys the elastislide instance 778 destroy : function( callback ) { 779 780 this._destroy( callback ); 781 782 } 783 784 }; 785 786 var logError = function( message ) { 787 788 if ( window.console ) { 789 790 window.console.error( message ); 791 792 } 793 794 }; 795 796 $.fn.elastislide = function( options ) { 797 798 var self = $.data( this, 'elastislide' ); 799 800 if ( typeof options === 'string' ) { 801 802 var args = Array.prototype.slice.call( arguments, 1 ); 803 804 this.each(function() { 805 806 if ( !self ) { 807 808 logError( "cannot call methods on elastislide prior to initialization; " + 809 "attempted to call method '" + options + "'" ); 810 return; 811 812 } 813 814 if ( !$.isFunction( self[options] ) || options.charAt(0) === "_" ) { 815 816 logError( "no such method '" + options + "' for elastislide self" ); 817 return; 818 819 } 820 821 self[ options ].apply( self, args ); 822 823 }); 824 825 } 826 else { 827 828 this.each(function() { 829 830 if ( self ) { 831 832 self._init(); 833 834 } 835 else { 836 837 self = $.data( this, 'elastislide', new $.Elastislide( options, this ) ); 838 839 } 840 841 }); 842 843 } 844 845 return self; 846 847 }; 848 849} )( jQuery, window );
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.