PageSourceSearch

https://www.flex-wiper.com.tw/js/jquery.elastislide.js

js flex-wiper.com.tw collected 2026-10-09 00:42:30 UTC 21,915 bytes, 849 lines download raw bytes

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.