1/** 2 * jquery.slitslider.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: 20 55 }; 56 57 // global 58 var $window = $( window ), 59 $document = $( document ), 60 Modernizr = window.Modernizr; 61 62 $.Slitslider = function( options, element ) { 63 64 this.$elWrapper = $( element ); 65 this._init( options ); 66 67 }; 68 69 $.Slitslider.defaults = { 70 // transitions speed 71 speed : 800, 72 // if true the item's slices will also animate the opacity value 73 optOpacity : false, 74 // amount (%) to translate both slices - adjust as necessary 75 translateFactor : 230, 76 // maximum possible angle 77 maxAngle : 25, 78 // maximum possible scale 79 maxScale : 2, 80 // slideshow on / off 81 autoplay : false, 82 // keyboard navigation 83 keyboard : true, 84 // time between transitions 85 interval : 4000, 86 // callbacks 87 onBeforeChange : function( slide, idx ) { return false; }, 88 onAfterChange : function( slide, idx ) { return false; } 89 }; 90 91 $.Slitslider.prototype = { 92 93 _init : function( options ) { 94 95 // options 96 this.options = $.extend( true, {}, $.Slitslider.defaults, options ); 97 98 // https://github.com/twitter/bootstrap/issues/2870 99 this.transEndEventNames = { 100 'WebkitTransition' : 'webkitTransitionEnd', 101 'MozTransition' : 'transitionend', 102 'OTransition' : 'oTransitionEnd', 103 'msTransition' : 'MSTransitionEnd', 104 'transition' : 'transitionend' 105 }; 106 this.transEndEventName = this.transEndEventNames[ Modernizr.prefixed( 'transition' ) ]; 107 // suport for css 3d transforms and css transitions 108 this.support = Modernizr.csstransitions && Modernizr.csstransforms3d; 109 // the slider 110 this.$el = this.$elWrapper.children( '.sl-slider' ); 111 // the slides 112 this.$slides = this.$el.children( '.sl-slide' ).hide(); 113 // total slides 114 this.slidesCount = this.$slides.length; 115 // current slide 116 this.current = 0; 117 // control if it's animating 118 this.isAnimating = false; 119 // get container size 120 this._getSize(); 121 // layout 122 this._layout(); 123 // load some events 124 this._loadEvents(); 125 // slideshow 126 if( this.options.autoplay ) { 127 128 this._startSlideshow(); 129 130 } 131 132 }, 133 // gets the current container width & height 134 _getSize : function() { 135 136 this.size = { 137 width : this.$elWrapper.outerWidth( true ), 138 height : this.$elWrapper.outerHeight( true ) 139 }; 140 141 }, 142 _layout : function() { 143 144 this.$slideWrapper = $( '<div class="sl-slides-wrapper" />' ); 145 146 // wrap the slides 147 this.$slides.wrapAll( this.$slideWrapper ).each( function( i ) { 148 149 var $slide = $( this ), 150 // vertical || horizontal 151 orientation = $slide.data( 'orientation' ); 152 153 $slide.addClass( 'sl-slide-' + orientation ) 154 .children() 155 .wrapAll( '<div class="sl-content-wrapper" />' ) 156 .wrapAll( '<div class="sl-content" />' ); 157 158 } ); 159 160 // set the right size of the slider/slides for the current window size 161 this._setSize(); 162 // show first slide 163 this.$slides.eq( this.current ).show(); 164 165 }, 166 _navigate : function( dir, pos ) { 167 168 if( this.isAnimating || this.slidesCount < 2 ) { 169 170 return false; 171 172 } 173 174 this.isAnimating = true; 175 176 var self = this, 177 $currentSlide = this.$slides.eq( this.current ); 178 179 // if position is passed 180 if( pos !== undefined ) { 181 182 this.current = pos; 183 184 } 185 // if not check the boundaries 186 else if( dir === 'next' ) { 187 188 this.current = this.current < this.slidesCount - 1 ? ++this.current : 0; 189 190 } 191 else if( dir === 'prev' ) { 192 193 this.current = this.current > 0 ? --this.current : this.slidesCount - 1; 194 195 } 196 197 this.options.onBeforeChange( $currentSlide, this.current ); 198 199 // next slide to be shown 200 var $nextSlide = this.$slides.eq( this.current ), 201 // the slide we want to cut and animate 202 $movingSlide = ( dir === 'next' ) ? $currentSlide : $nextSlide, 203 204 // the following are the data attrs set for each slide 205 configData = $movingSlide.data(), 206 config = {}; 207 208 config.orientation = configData.orientation || 'horizontal', 209 config.slice1angle = configData.slice1Rotation || 0, 210 config.slice1scale = configData.slice1Scale || 1, 211 config.slice2angle = configData.slice2Rotation || 0, 212 config.slice2scale = configData.slice2Scale || 1; 213
214 this._validateValues( config ); 215 216 var cssStyle = config.orientation === 'horizontal' ? { 217 marginTop : -this.size.height / 2 218 } : { 219 marginLeft : -this.size.width / 2 220 }, 221 // default slide's slices style 222 resetStyle = { 223 'transform' : 'translate(0%,0%) rotate(0deg) scale(1)', 224 opacity : 1 225 }, 226 // slice1 style 227 slice1Style = config.orientation === 'horizontal' ? { 228 'transform' : 'translateY(-' + this.options.translateFactor + '%) rotate(' + config.slice1angle + 'deg) scale(' + config.slice1scale + ')' 229 } : { 230 'transform' : 'translateX(-' + this.options.translateFactor + '%) rotate(' + config.slice1angle + 'deg) scale(' + config.slice1scale + ')' 231 }, 232 // slice2 style 233 slice2Style = config.orientation === 'horizontal' ? { 234 'transform' : 'translateY(' + this.options.translateFactor + '%) rotate(' + config.slice2angle + 'deg) scale(' + config.slice2scale + ')' 235 } : { 236 'transform' : 'translateX(' + this.options.translateFactor + '%) rotate(' + config.slice2angle + 'deg)
236scale(' + config.slice2scale + ')' 237 }; 238 239 if( this.options.optOpacity ) { 240 241 slice1Style.opacity = 0; 242 slice2Style.opacity = 0; 243 244 } 245 246 // we are adding the classes sl-trans-elems and sl-trans-back-elems to the slide that is either coming "next" 247 // or going "prev" according to the direction. 248 // the idea is to make it more interesting by giving some animations to the respective slide's elements 249 //( dir === 'next' ) ? $nextSlide.addClass( 'sl-trans-elems' ) : $currentSlide.addClass( 'sl-trans-back-elems' ); 250 251 $currentSlide.removeClass( 'sl-trans-elems' ); 252 253 var transitionProp = { 254 'transition' : 'all ' + this.options.speed + 'ms ease-in-out' 255 }; 256 257 // add the 2 slices and animate them 258 $movingSlide.css( 'z-index', this.slidesCount ) 259 .find( 'div.sl-content-wrapper' ) 260 .wrap( $( '<div class="sl-content-slice" />' ).css( transitionProp ) ) 261 .parent() 262 .cond( 263 dir === 'prev', 264 function() { 265 266 var slice = this; 267 this.css( slice1Style ); 268 setTimeout( function() { 269 270 slice.css( resetStyle ); 271 272 }, 50 ); 273 274 }, 275 function() { 276 277 var slice = this; 278 setTimeout( function() { 279 280 slice.css( slice1Style ); 281 282 }, 50 ); 283 284 } 285 ) 286 .clone() 287 .appendTo( $movingSlide ) 288 .cond( 289 dir === 'prev', 290 function() { 291 292 var slice = this; 293 this.css( slice2Style ); 294 setTimeout( function() { 295 296 $currentSlide.addClass( 'sl-trans-back-elems' ); 297 298 if( self.support ) { 299 300 slice.css( resetStyle ).on( self.transEndEventName, function() { 301 302 self._onEndNavigate( slice, $currentSlide, dir ); 303 304 } ); 305 306 } 307 else { 308 309 self._onEndNavigate( slice, $currentSlide, dir ); 310 311 } 312 313 }, 50 ); 314 315 }, 316 function() { 317 318 var slice = this; 319 setTimeout( function() { 320 321 $nextSlide.addClass( 'sl-trans-elems' ); 322 323 if( self.support ) { 324 325 slice.css( slice2Style ).on( self.transEndEventName, function() { 326 327 self._onEndNavigate( slice, $currentSlide, dir ); 328 329 } ); 330 331 } 332 else { 333 334 self._onEndNavigate( slice, $currentSlide, dir ); 335 336 } 337 338 }, 50 ); 339 340 } 341 ) 342 .find( 'div.sl-content-wrapper' ) 343 .css( cssStyle ); 344 345 $nextSlide.show(); 346 347 }, 348 _validateValues : function( config ) { 349 350 // OK, so we are restricting the angles and scale values here. 351 // This is to avoid the slices wrong sides to be shown. 352 // you can adjust these values as you wish but make sure you also ajust the 353 // paddings of the slides and also the options.translateFactor value and scale data attrs 354 if( config.slice1angle > this.options.maxAngle || config.slice1angle < -this.options.maxAngle ) { 355 356 config.slice1angle = this.options.maxAngle; 357 358 } 359 if( config.slice2angle > this.options.maxAngle || config.slice2angle < -this.options.maxAngle ) { 360 361 config.slice2angle = this.options.maxAngle; 362 363 } 364 if( config.slice1scale > this.options.maxScale || config.slice1scale <= 0 ) { 365 366 config.slice1scale = this.options.maxScale; 367 368 } 369 if( config.slice2scale > this.options.maxScale || config.slice2scale <= 0 ) { 370 371 config.slice2scale = this.options.maxScale; 372 373 } 374 if( config.orientation !== 'vertical' && config.orientation !== 'horizontal' ) { 375 376 config.orientation = 'horizontal' 377 378 } 379 380 }, 381 _onEndNavigate : function( $slice, $oldSlide, dir ) { 382 383 // reset previous slide's style after next slide is shown 384 var $slide = $slice.parent(), 385 removeClasses = 'sl-trans-elems sl-trans-back-elems'; 386 387 // remove second slide's slice 388 $slice.remove(); 389 // unwrap.. 390 $slide.css( 'z-index', 1 ) 391 .find( 'div.sl-content-wrapper' ) 392 .unwrap(); 393 394 // hide previous current slide 395 $oldSlide.hide().removeClass( removeClasses ); 396 $slide.removeClass( removeClasses ); 397 // now we can navigate again.. 398 this.isAnimating = false; 399 this.options.onAfterChange( $slide, this.current ); 400 401 }, 402 _setSize : function() { 403 404 // the slider and content wrappers will have the window's width and height 405 var cssStyle = { 406 width : this.size.width, 407 height : this.size.height 408 }; 409 410 this.$el.css( cssStyle ).find( 'div.sl-content-wrapper' ).css( cssStyle ); 411 412 }, 413 _loadEvents : function() { 414 415 var self = this; 416 417 $window.on( 'debouncedresize.slitslider', function( event ) { 418 419 // update size values 420 self._getSize(); 421 // set the sizes again 422 self._setSize(); 423 424 } ); 425 426 if ( this.options.keyboard ) { 427 428 $document.on( 'keydown.slitslider', function(e) { 429 430 var keyCode = e.keyCode || e.which, 431 arrow = { 432 left: 37, 433 up: 38, 434 right: 39, 435 down: 40 436 }; 437 438 switch (keyCode) { 439 440 case arrow.left : 441 442 self._stopSlideshow(); 443 self._navigate( 'prev' ); 444 break; 445 446 case arrow.right : 447 448 self._stopSlideshow(); 449 self._navigate( 'next' ); 450 break; 451 452 } 453 454 } ); 455 456 } 457 458 }, 459 _startSlideshow: function() { 460 461 var self = this; 462 463 this.slideshow = setTimeout( function() { 464 465 self._navigate( 'next' ); 466 467 if ( self.options.autoplay ) { 468 469 self._startSlideshow(); 470 471 } 472 473 }, this.options.interval ); 474 475 }, 476 _stopSlideshow: function() { 477 478 if ( this.options.autoplay ) { 479 480 clearTimeout( this.slideshow ); 481 this.isPlaying = false; 482 this.options.autoplay = false; 483 484 } 485 486 }, 487 _destroy : function( callback ) { 488 489 this.$el.off( '.slitslider' ).removeData( 'slitslider' ); 490 $window.off( '.slitslider' ); 491 $document.off( '.slitslider' ); 492 this.$slides.each( function( i ) { 493 494 var $slide = $( this ), 495 $content = $slide.find( 'div.sl-content' ).children();
496 497 $content.appendTo( $slide ); 498 $slide.children( 'div.sl-content-wrapper' ).remove(); 499 500 } ); 501 this.$slides.unwrap( this.$slideWrapper ).hide(); 502 this.$slides.eq( 0 ).show(); 503 if( callback ) { 504 505 callback.call(); 506 507 } 508 509 }, 510 // public methos: adds more slides to the slider 511 add : function( $slides, callback ) { 512 513 this.$slides = this.$slides.add( $slides ); 514 515 var self = this; 516 517 518 $slides.each( function( i ) { 519 520 var $slide = $( this ), 521 // vertical || horizontal 522 orientation = $slide.data( 'orientation' ); 523 524 $slide.hide().addClass( 'sl-slide-' + orientation ) 525 .children() 526 .wrapAll( '<div class="sl-content-wrapper" />' ) 527 .wrapAll( '<div class="sl-content" />' ) 528 .end() 529 .appendTo( self.$el.find( 'div.sl-slides-wrapper' ) ); 530 531 } ); 532 533 this._setSize(); 534 535 this.slidesCount = this.$slides.length; 536 537 if ( callback ) { 538 539 callback.call( $items ); 540 541 } 542 543 }, 544 // public method: shows next slide 545 next : function() { 546 547 this._stopSlideshow(); 548 this._navigate( 'next' ); 549 550 }, 551 // public method: shows previous slide 552 previous : function() { 553 554 this._stopSlideshow(); 555 this._navigate( 'prev' ); 556 557 }, 558 // public method: goes to a specific slide 559 jump : function( pos ) { 560 561 pos -= 1; 562 563 if( pos === this.current || pos >= this.slidesCount || pos < 0 ) { 564 565 return false; 566 567 } 568 569 this._stopSlideshow(); 570 this._navigate( pos > this.current ? 'next' : 'prev', pos ); 571 572 }, 573 // public method: starts the slideshow 574 // any call to next(), previous() or jump() will stop the slideshow 575 play : function() { 576 577 if( !this.isPlaying ) { 578 579 this.isPlaying = true; 580 581 this._navigate( 'next' ); 582 this.options.autoplay = true; 583 this._startSlideshow(); 584 585 } 586 587 }, 588 // public method: pauses the slideshow 589 pause : function() { 590 591 if( this.isPlaying ) { 592 593 this._stopSlideshow(); 594 595 } 596 597 }, 598 // public method: check if isAnimating is true 599 isActive : function() { 600 601 return this.isAnimating; 602 603 }, 604 // publicc methos: destroys the slicebox instance 605 destroy : function( callback ) { 606 607 this._destroy( callback ); 608 609 } 610 611 }; 612 613 var logError = function( message ) { 614 615 if ( window.console ) { 616 617 window.console.error( message ); 618 619 } 620 621 }; 622 623 $.fn.slitslider = function( options ) { 624 625 var self = $.data( this, 'slitslider' ); 626 627 if ( typeof options === 'string' ) { 628 629 var args = Array.prototype.slice.call( arguments, 1 ); 630 631 this.each(function() { 632 633 if ( !self ) { 634 635 logError( "cannot call methods on slitslider prior to initialization; " + 636 "attempted to call method '" + options + "'" ); 637 return; 638 639 } 640 641 if ( !$.isFunction( self[options] ) || options.charAt(0) === "_" ) { 642 643 logError( "no such method '" + options + "' for slitslider self" ); 644 return; 645 646 } 647 648 self[ options ].apply( self, args ); 649 650 }); 651 652 } 653 else { 654 655 this.each(function() { 656 657 if ( self ) { 658 659 self._init(); 660 661 } 662 else { 663 664 self = $.data( this, 'slitslider', new $.Slitslider( options, this ) ); 665 666 } 667 668 }); 669 670 } 671 672 return self; 673 674 }; 675 676} )( 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.