Team:UESTC/jquery.bookblock.js

From 2013.igem.org

/**

* jquery.bookblock.js v1.0.2
* http://www.codrops.com
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2012, Codrops
* http://www.codrops.com
*/

(function($, window, undefined) {

'use strict';

/* * debouncedresize: special jQuery event that happens once after a window resize * * latest version and complete README available on Github: * https://github.com/louisremi/jquery-smartresize/blob/master/jquery.debouncedresize.js * * Copyright 2011 @louis_remi * Licensed under the MIT license. */ var $event = $.event, $special, resizeTimeout;

$special = $event.special.debouncedresize = { setup: function() { $( this ).on( "resize", $special.handler ); }, teardown: function() { $( this ).off( "resize", $special.handler ); }, handler: function( event, execAsap ) { // Save the context var context = this, args = arguments, dispatch = function() { // set correct event type event.type = "debouncedresize"; $event.dispatch.apply( context, args ); };

if ( resizeTimeout ) { clearTimeout( resizeTimeout ); }

execAsap ? dispatch() : resizeTimeout = setTimeout( dispatch, $special.threshold ); }, threshold: 150 };

// global var $window = $(window), Modernizr = window.Modernizr;

$.BookBlock = function(options, element) {

this.$el = $(element); this._init(options);

};

// the options $.BookBlock.defaults = { // speed for the flip transition in ms speed : 1000, // easing for the flip transition easing : 'ease-in-out', // if set to true, both the flipping page and the sides will have an overlay to simulate shadows shadows : true, // opacity value for the "shadow" on both sides (when the flipping page is over it) // value : 0.1 - 1 shadowSides : 0.2, // opacity value for the "shadow" on the flipping page (while it is flipping) // value : 0.1 - 1 shadowFlip : 0.1, // perspective value perspective : 1300, // if we should show the first item after reaching the end circular : false, // if we want to specify a selector that triggers the next() function. example: '#bb-nav-next' nextEl : , // if we want to specify a selector that triggers the prev() function prevEl : , // autoplay. If true it overwrites the circular option to true autoplay : false, // time (ms) between page switch, if autoplay is true interval : 3000, //if we want to navigate the slides with the keyboard arrows keyboard : true, // callback after the flip transition // old is the index of the previous item // page is the current item's index // isLimit is true if the current page is the last one (or the first one) onEndFlip : function(old, page, isLimit) { return false; }, // callback before the flip transition // page is the current item's index onBeforeFlip : function(page) { return false; } };

$.BookBlock.prototype = {

_init: function(options) {

// options this.options = $.extend(true, {}, $.BookBlock.defaults, options); // set the perspective this.$el.css('perspective', this.options.perspective); // items this.$items = this.$el.children('.bb-item'); // total items this.itemsCount = this.$items.length; // current item's index this.current = 0; // previous item's index this.previous = -1; // show first item this.$current = this.$items.eq(this.current).show(); // get width of this.$el // this will be necessary to create the flipping layout this.elWidth = this.$el.width(); var transEndEventNames = { 'WebkitTransition': 'webkitTransitionEnd', 'MozTransition': 'transitionend', 'OTransition': 'oTransitionEnd', 'msTransition': 'MSTransitionEnd', 'transition': 'transitionend' }; this.transEndEventName = transEndEventNames[Modernizr.prefixed('transition')] + '.bookblock'; // support (3dtransforms && transitions) this.support = Modernizr.csstransitions && Modernizr.csstransforms3d; // initialize/bind some events this._initEvents(); // start slideshow if (this.options.autoplay) {

this.options.circular = true; this._startSlideshow();

}

}, _initEvents: function() {

var self = this;

if (this.options.nextEl !== ) {

$(this.options.nextEl).on('click.bookblock', function() {

self._action('next'); return false;

});

}

if (this.options.prevEl !== ) {

$(this.options.prevEl).on('click.bookblock', function() {

self._action('prev'); return false;

});

}

if (this.options.keyboard == true) { $(document).keydown(function(e) { var keyCode = e.keyCode || e.which, arrow = { left : 37, up : 38, right : 39, down : 40 };

switch (keyCode) { case arrow.left: self._action('prev'); break; case arrow.right: self._action('next'); break; } }); }

$window.on( 'debouncedresize', function() {

// update width value self.elWidth = self.$el.width();

} )

}, _action : function(dir, page) {

this._stopSlideshow(); this._navigate(dir, page);

}, _navigate: function(dir, page) {

if (this.isAnimating) { return false; }

// callback trigger this.options.onBeforeFlip(this.current);

this.isAnimating = true; this.$current = this.$items.eq(this.current);

if (page !== undefined) {

this.current = page;

} else if (dir === 'next') {

if (!this.options.circular && this.current === this.itemsCount - 1) {

this.end = true;

} else {

this.previous = this.current; this.current = this.current < this.itemsCount - 1 ? this.current + 1 : 0;

}

} else if (dir === 'prev') {

if (!this.options.circular && this.current === 0) {

this.end = true;

} else {

this.previous = this.current; this.current = this.current > 0 ? this.current - 1 : this.itemsCount - 1;

}

}

this.$nextItem = !this.options.circular && this.end ? this.$current : this.$items.eq(this.current);

if (!this.support) {

this._layoutNoSupport(dir);

} else {

this._layout(dir);

}

}, // with no support we consider no 3d transforms and transitions _layoutNoSupport: function(dir) {

this.$items.hide(); this.$nextItem.show(); this.end = false; this.isAnimating = false; var isLimit = dir === 'next' && this.current === this.itemsCount - 1 || dir === 'prev' && this.current === 0; // callback trigger this.options.onEndFlip(this.previous, this.current, isLimit);

}, // creates the necessary layout for the 3d animation, and triggers the transitions _layout: function(dir) {

var self = this,

// basic structure: // 1 element for the left side. $s_left = this._addSide('left', dir), // 1 element for the flipping/middle page $s_middle = this._addSide('middle', dir), // 1 element for the right side $s_right = this._addSide('right', dir), // overlays $o_left = $s_left.find('div.bb-overlay'), $o_middle_f = $s_middle.find('div.bb-flipoverlay:first'), $o_middle_b = $s_middle.find('div.bb-flipoverlay:last'), $o_right = $s_right.find('div.bb-overlay'), speed = this.end ? 400 : this.options.speed;

this.$items.hide(); this.$el.prepend($s_left, $s_middle, $s_right);

$s_middle.css({ transition: 'all ' + speed + 'ms ' + this.options.easing }).on(this.transEndEventName, function(event) {

if (event.target.className === 'bb-page') {

self.$el.children('div.bb-page').remove(); self.$nextItem.show();

self.end = false; self.isAnimating = false;

var isLimit = dir === 'next' && self.current === self.itemsCount - 1 || dir === 'prev' && self.current === 0;

// callback trigger self.options.onEndFlip(self.previous, self.current, isLimit);

}

});

if (dir === 'prev') { $s_middle.css({ transform: 'rotateY(-180deg)' }); }

// overlays if (this.options.shadows && !this.end) {

var o_left_style = (dir === 'next') ? { transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' + ' ' + this.options.speed / 2 + 'ms' } : { transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear', opacity: this.options.shadowSides }, o_middle_f_style = (dir === 'next') ? { transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' } : { transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' + ' ' + this.options.speed / 2 + 'ms', opacity: this.options.shadowFlip }, o_middle_b_style = (dir === 'next') ? { transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' + ' ' + this.options.speed / 2 + 'ms', opacity: this.options.shadowFlip } : { transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' }, o_right_style = (dir === 'next') ? { transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear', opacity: this.options.shadowSides } : { transition: 'opacity ' + this.options.speed / 2 + 'ms ' + 'linear' + ' ' + this.options.speed / 2 + 'ms' };

$o_middle_f.css(o_middle_f_style); $o_middle_b.css(o_middle_b_style); $o_left.css(o_left_style); $o_right.css(o_right_style);

}

setTimeout(function() {

var style = dir === 'next' ? 'rotateY(-180deg)' : 'rotateY(0deg)';

if (self.end) { // first && last pages lift up 15 deg when we can't go further style = dir === 'next' ? 'rotateY(-15deg)' : 'rotateY(-165deg)'; }

$s_middle.css({transform: style});

// overlays if (self.options.shadows && !self.end) {

$o_middle_f.css({ opacity: dir === 'next' ? self.options.shadowFlip : 0 });

$o_middle_b.css({ opacity: dir === 'next' ? 0 : self.options.shadowFlip });

$o_left.css({ opacity: dir === 'next' ? self.options.shadowSides : 0 });

$o_right.css({ opacity: dir === 'next' ? 0 : self.options.shadowSides });

}


}, 30);

}, // adds the necessary sides (bb-page) to the layout _addSide: function(side, dir) {

var $side;

switch (side) {

case 'left': /*

dir==='next' ? [content of current page] : [content of next page]

*/

$side = $('
' + (dir === 'next' ? this.$current.html() : this.$nextItem.html()) + '
').css('z-index', 102);

break;

case 'middle': /*

dir==='next' ? [content of current page] : [content of next page]

dir==='next' ? [content of next page] : [content of current page]

*/

$side = $('
' + (dir === 'next' ? this.$current.html() : this.$nextItem.html()) + '
' + (dir === 'next' ? this.$nextItem.html() : this.$current.html()) + '
').css('z-index', 103);

break;

case 'right': /*

dir==='next' ? [content of next page] : [content of current page]

*/

$side = $('
' + (dir === 'next' ? this.$nextItem.html() : this.$current.html()) + '
').css('z-index', 101);

break;

}

return $side;

}, _startSlideshow: function() {

var self = this;

this.slideshow = setTimeout(function() {

self._navigate('next');

if (self.options.autoplay) { self._startSlideshow(); }

}, this.options.interval);

}, _stopSlideshow: function() {

if (this.options.autoplay) {

clearTimeout(this.slideshow); this.options.autoplay = false;

}

}, // public method: flips next next: function() { this._action('next'); }, // public method: flips back prev: function() { this._action('prev'); }, // public method: goes to a specific page jump: function(page) {

page -= 1;

if (page === this.current || page >= this.itemsCount || page < 0) { return false; }

this._action(page > this.current ? 'next' : 'prev', page);

}, // public method: check if isAnimating is true isActive: function() { return this.isAnimating; }, // public method: dynamically adds new elements // call this method after inserting new "bb-item" elements inside the BookBlock update : function () {

var $currentItem = this.$items.eq( this.current ); this.$items = this.$el.children('.bb-item'); this.itemsCount = this.$items.length; this.current = $currentItem.index();

}

};

var logError = function(message) { if (window.console) { window.console.error(message); } };

$.fn.bookblock = function(options) {

var instance = $.data(this, 'bookblock');

if (typeof options === 'string') {

var args = Array.prototype.slice.call(arguments, 1);

this.each(function() {

if (!instance) {

logError("cannot call methods on bookblock prior to initialization; " + "attempted to call method '" + options + "'"); return;

}

if (!$.isFunction(instance[options]) || options.charAt(0) === "_") {

logError("no such method '" + options + "' for bookblock instance"); return;

}

instance[options].apply(instance, args);

});

} else {

this.each(function() {

if (instance) {

instance._init();

} else {

instance = $.data(this, 'bookblock', new $.BookBlock(options, this));

}

});

}

return instance;

};

})(jQuery, window);