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 = $('break;
case 'middle': /*
dir==='next' ? [content of current page] : [content of next page]
dir==='next' ? [content of next page] : [content of current page]
*/
$side = $('break;
case 'right': /*
dir==='next' ? [content of next page] : [content of current page]
*/
$side = $('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);