1/** 2 * jquery.bookblock.js v2.0.1 3 * http://www.codrops.com 4 * 5 * Licensed under the MIT license. 6 * http://www.opensource.org/licenses/mit-license.php 7 * 8 * Copyright 2013, Codrops 9 * http://www.codrops.com 10 */ 11;( function( $, window, undefined ) { 12 13 'use strict'; 14 15 // global 16 var $window = $(window), 17 Modernizr = window.Modernizr; 18 19 // https://gist.github.com/edankwan/4389601 20 Modernizr.addTest('csstransformspreserve3d', function () { 21 var prop = Modernizr.prefixed('transformStyle'); 22 var val = 'preserve-3d'; 23 var computedStyle; 24 if(!prop) return false; 25 26 prop = prop.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-'); 27 28 Modernizr.testStyles('#modernizr{' + prop + ':' + val + ';}', function (el, rule) { 29 computedStyle = window.getComputedStyle ? getComputedStyle(el, null).getPropertyValue(prop) : ''; 30 }); 31 32 return (computedStyle === val); 33 }); 34 35 /* 36 * debouncedresize: special jQuery event that happens once after a window resize 37 * 38 * latest version and complete README available on Github: 39 * https://github.com/louisremi/jquery-smartresize 40 * 41 * Copyright 2012 @louis_remi 42 * Licensed under the MIT license. 43 * 44 * This saved you an hour of work? 45 * Send me music http://www.amazon.co.uk/wishlist/HNTU0468LQON 46 */ 47 var $event = $.event, 48 $special, 49 resizeTimeout; 50 51 $special = $event.special.debouncedresize = { 52 setup: function() { 53 $( this ).on( "resize", $special.handler ); 54 }, 55 teardown: function() { 56 $( this ).off( "resize", $special.handler ); 57 }, 58 handler: function( event, execAsap ) { 59 // Save the context 60 var context = this, 61 args = arguments, 62 dispatch = function() { 63 // set correct event type 64 event.type = "debouncedresize"; 65 $event.dispatch.apply( context, args ); 66 }; 67 68 if ( resizeTimeout ) { 69 clearTimeout( resizeTimeout ); 70 } 71 72 execAsap ? 73 dispatch() : 74 resizeTimeout = setTimeout( dispatch, $special.threshold ); 75 }, 76 threshold: 150 77 }; 78 79 $.BookBlock = function( options, element ) { 80 this.$el = $( element ); 81 this._init( options ); 82 }; 83 84 // the options 85 $.BookBlock.defaults = { 86 // page to start on 87 startPage : 1, 88 // vertical or horizontal flip 89 orientation : 'vertical', 90 // ltr (left to right) or rtl (right to left) 91 direction : 'ltr', 92 // speed for the flip transition in ms 93 speed : 1000, 94 // easing for the flip transition 95 easing : 'ease-in-out', 96 // if set to true, both the flipping page and the sides will have an overlay to simulate shadows 97 shadows : true, 98 // opacity value for the "shadow" on both sides (when the flipping page is over it) 99 // value : 0.1 - 1 100 shadowSides : 0.2, 101 // opacity value for the "shadow" on the flipping page (while it is flipping) 102 // value : 0.1 - 1 103 shadowFlip : 0.1, 104 // if we should show the first item after reaching the end 105 circular : false, 106 // if we want to specify a selector that triggers the next() function. example: ´#bb-nav-next´ 107 nextEl : '', 108 // if we want to specify a selector that triggers the prev() function 109 prevEl : '', 110 // autoplay. If true it overwrites the circular option to true 111 autoplay : false, 112 // time (ms) between page switch, if autoplay is true 113 interval : 3000, 114 // callback after the flip transition 115 // old is the index of the previous item 116 // page is the current item´s index 117 // isLimit is true if the current page is the last one (or the first one) 118 onEndFlip : function(old, page, isLimit) { return false; }, 119 // callback before the flip transition 120 // page is the current item´s index 121 onBeforeFlip : function(page) { return false; } 122 }; 123 124 $.BookBlock.prototype = { 125 _init : function(options) { 126 // options 127 this.options = $.extend( true, {}, $.BookBlock.defaults, options ); 128 // orientation class 129 this.$el.addClass( 'bb-' + this.options.orientation ); 130 // items 131 this.$items = this.$el.children( '.bb-item' ).hide(); 132 // total items 133 this.itemsCount = this.$items.length; 134 // current item´s index 135 if ( (this.options.startPage > 0) && (this.options.startPage <= this.itemsCount) ) { 136 this.current = (this.options.startPage - 1); 137 } else { 138 logError('startPage option is out of range'); 139 this.current = 0; 140 } 141 // previous item´s index 142 this.previous = -1; 143 // show first item 144 this.$current = this.$items.eq( this.current ).show(); 145 // get width of this.$el 146 // this will be necessary to create the flipping layout 147 this.elWidth = this.$el.width(); 148 var transEndEventNames = { 149 'WebkitTransition': 'webkitTransitionEnd', 150 'MozTransition': 'transitionend', 151 'OTransition': 'oTransitionEnd', 152 'msTransition': 'MSTransitionEnd', 153 'transition': 'transitionend' 154 }; 155 this.transEndEventName = transEndEventNames[Modernizr.prefixed( 'transition' )] + '.bookblock'; 156 // support css 3d transforms && css transitions && Modernizr.csstransformspreserve3d 157 this.support = Modernizr.csstransitions && Modernizr.csstransforms3d && Modernizr.csstransformspreserve3d; 158 // initialize/bind some events 159 this._initEvents(); 160 // start slideshow 161 if ( this.options.autoplay ) { 162 this.options.circular = true; 163 this._startSlideshow(); 164 } 165 }, 166 _initEvents : function() { 167 168 var self = this; 169 170 if ( this.options.nextEl !== '' ) { 171 $( this.options.nextEl ).on( 'click.bookblock touchstart.bookblock', function() { self._action( 'next' ); return false; } ); 172 } 173 174 if ( this.options.prevEl !== '' ) { 175 $( this.options.prevEl ).on( 'click.bookblock touchstart.bookblock', function() { self._action( 'prev' ); return false; } ); 176 } 177 178 $window.on( 'debouncedresize', function() { 179 // update width value 180 self.elWidth = self.$el.width(); 181 } ); 182 183 }, 184 _action : function( dir, page ) { 185 this._stopSlideshow(); 186 this._navigate( dir, page ); 187 }, 188 _navigate : function( dir, page ) { 189 190 if ( this.isAnimating ) { 191 return false;
192 } 193 194 // callback trigger 195 this.options.onBeforeFlip( this.current ); 196 197 this.isAnimating = true; 198 // update current value 199 this.$current = this.$items.eq( this.current ); 200 201 if ( page !== undefined ) { 202 this.current = page; 203 } 204 else if ( dir === 'next' && this.options.direction === 'ltr' || dir === 'prev' && this.options.direction === 'rtl' ) { 205 if ( !this.options.circular && this.current === this.itemsCount - 1 ) { 206 this.end = true; 207 } 208 else { 209 this.previous = this.current; 210 this.current = this.current < this.itemsCount - 1 ? this.current + 1 : 0; 211 } 212 } 213 else if ( dir === 'prev' && this.options.direction === 'ltr' || dir === 'next' && this.options.direction === 'rtl' ) { 214 if ( !this.options.circular && this.current === 0 ) { 215 this.end = true; 216 } 217 else { 218 this.previous = this.current; 219 this.current = this.current > 0 ? this.current - 1 : this.itemsCount - 1; 220 } 221 } 222 223 this.$nextItem = !this.options.circular && this.end ? this.$current : this.$items.eq( this.current ); 224 225 if ( !this.support ) { 226 this._layoutNoSupport( dir ); 227 } else { 228 this._layout( dir ); 229 } 230 231 }, 232 _layoutNoSupport : function(dir) { 233 this.$items.hide(); 234 this.$nextItem.show(); 235 this.end = false; 236 this.isAnimating = false; 237 var isLimit = dir === 'next' && this.current === this.itemsCount - 1 || dir === 'prev' && this.current === 0; 238 // callback trigger 239 this.options.onEndFlip( this.previous, this.current, isLimit ); 240 }, 241 // creates the necessary layout for the 3d structure 242 _layout : function(dir) { 243 244 var self = this, 245 // basic structure: 1 element for the left side. 246 $s_left = this._addSide( 'left', dir ), 247 // 1 element for the flipping/middle page 248 $s_middle = this._addSide( 'middle', dir ), 249 // 1 element for the right side 250 $s_right = this._addSide( 'right', dir ), 251 // overlays 252 $o_left = $s_left.find( 'div.bb-overlay' ), 253 $o_middle_f = $s_middle.find( 'div.bb-flipoverlay:first' ), 254 $o_middle_b = $s_middle.find( 'div.bb-flipoverlay:last' ), 255 $o_right = $s_right.find( 'div.bb-overlay' ), 256 speed = this.end ? 400 : this.options.speed; 257 258 this.$items.hide(); 259 this.$el.prepend( $s_left, $s_middle, $s_right ); 260 261 $s_middle.css({ 262 transitionDuration: speed + 'ms', 263 transitionTimingFunction : this.options.easing 264 }).on( this.transEndEventName, function( event ) { 265 if ( $( event.target ).hasClass( 'bb-page' ) ) { 266 self.$el.children( '.bb-page' ).remove(); 267 self.$nextItem.show(); 268 self.end = false; 269 self.isAnimating = false; 270 var isLimit = dir === 'next' && self.current === self.itemsCount - 1 || dir === 'prev' && self.current === 0; 271 // callback trigger 272 self.options.onEndFlip( self.previous, self.current, isLimit ); 273 } 274 }); 275 276 if ( dir === 'prev' ) { 277 $s_middle.addClass( 'bb-flip-initial' ); 278 } 279 280 // overlays 281 if (this.options.shadows && !this.end) { 282 283 var o_left_style = (dir === 'next') ? { 284 transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' + ' ' + this.options.speed / 2 + 'ms' 285 } : { 286 transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear', 287 opacity: this.options.shadowSides 288 }, 289 o_middle_f_style = (dir === 'next') ? { 290 transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' 291 } : { 292 transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' + ' ' + this.options.speed / 2 + 'ms', 293 opacity: this.options.shadowFlip 294 }, 295 o_middle_b_style = (dir === 'next') ? { 296 transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' + ' ' + this.options.speed / 2 + 'ms', 297 opacity: this.options.shadowFlip 298 } : { 299 transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' 300 }, 301 o_right_style = (dir === 'next') ? { 302 transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear', 303 opacity: this.options.shadowSides 304 } : { 305 transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' + ' ' + this.options.speed / 2 + 'ms' 306 }; 307 308 $o_middle_f.css(o_middle_f_style); 309 $o_middle_b.css(o_middle_b_style); 310 $o_left.css(o_left_style); 311 $o_right.css(o_right_style); 312 313 } 314 315 setTimeout( function() { 316 // first && last pages lift slightly up when we can't go further 317 $s_middle.addClass( self.end ? 'bb-flip-' + dir + '-end' : 'bb-flip-' + dir ); 318 319 // overlays 320 if ( self.options.shadows && !self.end ) { 321 322 $o_middle_f.css({ 323 opacity: dir === 'next' ? self.options.shadowFlip : 0 324 }); 325 326 $o_middle_b.css({ 327 opacity: dir === 'next' ? 0 : self.options.shadowFlip 328 }); 329 330 $o_left.css({ 331 opacity: dir === 'next' ? self.options.shadowSides : 0 332 }); 333 334 $o_right.css({ 335 opacity: dir === 'next' ? 0 : self.options.shadowSides 336 }); 337 338 } 339 }, 25 ); 340 }, 341 // adds the necessary sides (bb-page) to the layout 342 _addSide : function( side, dir ) { 343 var $side; 344 345 switch (side) { 346 case 'left': 347 /* 348 <div class="bb-page" style="z-index:102;"> 349 <div class="bb-back"> 350 <div class="bb-outer"> 351 <div class="bb-content"> 352 <div class="bb-inner"> 353 dir==='next' ? [content of current page] : [content of next page] 354 </div> 355 </div> 356 <div class="bb-overlay"></div> 357 </div> 358 </div> 359 </div> 360 */
361 $side = $('<div class="bb-page"><div class="bb-back"><div class="bb-outer"><div class="bb-content"><div class="bb-inner">' + ( dir === 'next' ? this.$current.html() : this.$nextItem.html() ) + '</div></div><div class="bb-overlay"></div></div></div></div>').css( 'z-index', 102 ); 362 break; 363 case 'middle': 364 /* 365 <div class="bb-page" style="z-index:103;"> 366 <div class="bb-front"> 367 <div class="bb-outer"> 368 <div class="bb-content"> 369 <div class="bb-inner"> 370 dir==='next' ? [content of current page] : [content of next page] 371 </div> 372 </div> 373 <div class="bb-flipoverlay"></div> 374 </div> 375 </div> 376 <div class="bb-back"> 377 <div class="bb-outer"> 378 <div class="bb-content"> 379 <div class="bb-inner"> 380 dir==='next' ? [content of next page] : [content of current page] 381 </div> 382 </div> 383 <div class="bb-flipoverlay"></div> 384 </div> 385 </div> 386 </div> 387 */ 388 $side = $('<div class="bb-page"><div class="bb-front"><div class="bb-outer"><div class="bb-content"><div class="bb-inner">' + (dir === 'next' ? this.$current.html() : this.$nextItem.html()) + '</div></div><div class="bb-flipoverlay"></div></div></div><div class="bb-back"><div class="bb-outer"><div class="bb-content" style="width:' + this.elWidth + 'px"><div class="bb-inner">' + ( dir === 'next' ? this.$nextItem.html() : this.$current.html() ) + '</div></div><div class="bb-flipoverlay"></div></div></div></div>').css( 'z-index', 103 ); 389 break; 390 case 'right': 391 /* 392 <div class="bb-page" style="z-index:101;"> 393 <div class="bb-front"> 394 <div class="bb-outer"> 395 <div class="bb-content"> 396 <div class="bb-inner"> 397 dir==='next' ? [content of next page] : [content of current page] 398 </div> 399 </div> 400 <div class="bb-overlay"></div> 401 </div> 402 </div> 403 </div> 404 */ 405 $side = $('<div class="bb-page"><div class="bb-front"><div class="bb-outer"><div class="bb-content"><div class="bb-inner">' + ( dir === 'next' ? this.$nextItem.html() : this.$current.html() ) + '</div></div><div class="bb-overlay"></div></div></div></div>').css( 'z-index', 101 ); 406 break; 407 } 408 409 return $side; 410 }, 411 _startSlideshow : function() { 412 var self = this; 413 this.slideshow = setTimeout( function() { 414 self._navigate( 'next' ); 415 if ( self.options.autoplay ) { 416 self._startSlideshow(); 417 } 418 }, this.options.interval ); 419 }, 420 _stopSlideshow : function() { 421 if ( this.options.autoplay ) { 422 clearTimeout( this.slideshow ); 423 this.options.autoplay = false; 424 } 425 }, 426 // public method: flips next 427 next : function() { 428 this._action( this.options.direction === 'ltr' ? 'next' : 'prev' ); 429 }, 430 // public method: flips back 431 prev : function() { 432 this._action( this.options.direction === 'ltr' ? 'prev' : 'next' ); 433 }, 434 // public method: goes to a specific page 435 jump : function( page ) { 436 437 page -= 1; 438 439 if ( page === this.current || page >= this.itemsCount || page < 0 ) { 440 return false; 441 } 442 443 var dir; 444 if( this.options.direction === 'ltr' ) { 445 dir = page > this.current ? 'next' : 'prev'; 446 } 447 else { 448 dir = page > this.current ? 'prev' : 'next'; 449 } 450 this._action( dir, page ); 451 452 }, 453 // public method: goes to the last page 454 last : function() { 455 this.jump( this.itemsCount ); 456 }, 457 // public method: goes to the first page 458 first : function() { 459 this.jump( 1 ); 460 }, 461 // public method: check if isAnimating is true 462 isActive: function() { 463 return this.isAnimating; 464 }, 465 // public method: dynamically adds new elements 466 // call this method after inserting new "bb-item" elements inside the BookBlock 467 update : function () { 468 var $currentItem = this.$items.eq( this.current ); 469 this.$items = this.$el.children( '.bb-item' ); 470 this.itemsCount = this.$items.length; 471 this.current = $currentItem.index(); 472 }, 473 destroy : function() { 474 if ( this.options.autoplay ) { 475 this._stopSlideshow(); 476 } 477 this.$el.removeClass( 'bb-' + this.options.orientation ); 478 this.$items.show(); 479 480 if ( this.options.nextEl !== '' ) { 481 $( this.options.nextEl ).off( '.bookblock' ); 482 } 483 484 if ( this.options.prevEl !== '' ) { 485 $( this.options.prevEl ).off( '.bookblock' ); 486 } 487 488 $window.off( 'debouncedresize' ); 489 } 490 } 491 492 var logError = function( message ) { 493 if ( window.console ) { 494 window.console.error( message ); 495 } 496 }; 497 498 $.fn.bookblock = function( options ) { 499 if ( typeof options === 'string' ) { 500 var args = Array.prototype.slice.call( arguments, 1 ); 501 this.each(function() { 502 var instance = $.data( this, 'bookblock' ); 503 if ( !instance ) { 504 logError( "cannot call methods on bookblock prior to initialization; " + 505 "attempted to call method '" + options + "'" ); 506 return; 507 } 508 if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) { 509 logError( "no such method '" + options + "' for bookblock instance" ); 510 return; 511 } 512 instance[ options ].apply( instance, args ); 513 }); 514 } 515 else { 516 this.each(function() { 517 var instance = $.data( this, 'bookblock' ); 518 if ( instance ) { 519 instance._init(); 520 } 521 else { 522 instance = $.data( this, 'bookblock', new $.BookBlock( options, this ) ); 523 } 524 }); 525 } 526 return this; 527 }; 528 529} )( 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.