/*
* jQuery Booklet Plugin
* Copyright (c) 2010 W. Grauvogel (http://builtbywill.com/)
*
* Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
* and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
*
* Version : 1.2.0
*
* Originally based on the work of:
* 1) Charles Mangin (http://clickheredammit.com/pageflip/)
*/
;(function($) {
$.fn.booklet = function(options){
var o = $.extend({}, $.fn.booklet.defaults, options);
return $(this).each(function()
{
var command, config, obj, id, i, target;
//option type string - api call
if(typeof options == 'string')
{
//check if booklet has been initialized
if($(this).data('booklet')){
command = options.toLowerCase();
obj = $.fn.booklet.interfaces[$(this).data('id')];
if(command == 'next'){ obj.next() }
else if(command == 'prev'){ obj.prev() }
}
}
//option type number - api call
else if(typeof options == 'number')
{
//check if booklet has been initialized
if($(this).data('booklet')){
target = options;
obj = $.fn.booklet.interfaces[$(this).data('id')];
if(target % 2 != 0) {
target-= 1;
}
obj.gotoPage(target);
}
}
//else build new booklet
else
{
config = $.extend(true, {}, o);
// Determine ID (Reuse array slots if possible)
id = $.fn.booklet.interfaces.length;
for(i = 0; i < id; i++)
{
if(typeof $.fn.booklet.interfaces[i] == 'undefined'){ id = i; break; }
}
// Instantiate the booklet
obj = new booklet($(this), config, id);
// Add API references
$.fn.booklet.interfaces[id] = obj;
}
});
}
function booklet(target, options, id){
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//VARS + STRUCTURE
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
var self, opts, b, src,
hash, i, j, p, diff, busy, init, rhover, lhover, h, a, playing,
titles = new Array(), chapters = new Array(),
pN, p0, p1, p2, p3, p4, pNwrap, p0wrap, p1wrap, p2wrap, p3wrap, p4wrap, wraps, sF, sB,
p3drag, p0drag, temp, relativeX,
overlaysB, overlayN, overlayP, tabs, tabN, tabP, arrows, arrowN, arrowP, next, prev, ctrlsN, ctrlsP,
menu, chapter, dd, ddUL, ddH, ddLI, ddA, ddT, ddC, ddCUL, ddCH, ddCLI, ddCA, ddCT,
empty = '
', blank = ''
;
busy = false;
playing = false;
init = false;
rhover = lhover = false;
self = this;
self.options = options;
self.id = id;
self.hash = '';
opts = self.options;
b = target.addClass('booklet');
src = b.children('.b-load');
//save page titles and chapter names, add page numbers
initPages();
//store data for api calls
b.data('booklet',true);
b.data('id', id);
b.data('total', src.children().length);
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SETUP OPTIONS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//set width + height
if(!opts.width){
opts.width = b.width();
}else if(typeof opts.width == 'string' && opts.width.indexOf("%") != -1){
opts.wPercent = true;
opts.wOrig = opts.width;
opts.width = (opts.width.replace('%','')/100) * parseFloat(b.parent().css('width'));
}
if(!opts.height){
opts.height = b.height();
}else if(typeof opts.height == 'string' && opts.height.indexOf("%") != -1){
opts.hPercent = true;
opts.hOrig = opts.height;
opts.height = (opts.height.replace('%','')/100) * parseFloat(b.parent().css('height'));
}
b.width(opts.width);
b.height(opts.height);
//save page sizes and other vars
opts.pWidth = opts.width/2;
opts.pWidthN = '-'+(opts.pWidth)+'px';
opts.pWidthH = opts.pWidth/2;
opts.pHeight = opts.height;
opts.pTotal = src.children().length;
opts.speedH = opts.speed/2;
//set startingPage
if(opts.direction == 'LTR'){
opts.curr = 0;
}else if(opts.direction == 'RTL'){
opts.curr = opts.pTotal-2;
}
if(!isNaN(opts.startingPage) && opts.startingPage <= opts.pTotal && opts.startingPage > 0){
if((opts.startingPage % 2) != 0){opts.startingPage--};
opts.curr = opts.startingPage;
}
//set position
if(opts.closed && opts.autoCenter){
if(opts.curr == 0){
b.width(opts.pWidth);
}else if(opts.curr >= opts.pTotal-2){
b.width(opts.pWidth);
}
}
//set booklet opts.name
if(opts.name){
document.title = opts.name;
}else{
opts.name = document.title;
}
//save shadow widths for anim
if(opts.shadows){
opts.shadowTopFwdWidth = '-'+opts.shadowTopFwdWidth+'px';
opts.shadowTopBackWidth = '-'+opts.shadowTopBackWidth+'px';
}
//setup menu
if(opts.menu){
menu = $(opts.menu).addClass('b-menu');
p = opts.curr;
//setup page selctor
if(opts.pageSelector){
//add selector
dd = $(''+ (p+1) +' - '+ (p+2) +'
').appendTo(menu);
ddUL = $('').appendTo(dd).empty().css('height','auto');
//loop through all pages
for(i=0; i < opts.pTotal; i+=2){
j = i;
//nums for normal view
nums = (j+1) +'-'+ (j+2);
if(opts.closed){
//nums for closed book
j--;
if(i==0){nums='1'}
else if(i==opts.pTotal-2){nums=opts.pTotal-2}
else {nums = (j+1) +'-'+ (j+2);}
//nums for closed book with covers
if(opts.covers){
j--;
if(i==0){nums=''}
else if(i==opts.pTotal-2){nums=''}
else {nums = (j+1) +'-'+ (j+2);}
}
}
//nums for RTL direction
if(opts.direction == 'RTL'){
nums = (Math.abs(j - opts.pTotal)-1) +' - '+ ((Math.abs(j - opts.pTotal)));
if(opts.closed){
if(i==opts.pTotal-2){nums='1'}
else if(i==0){nums=opts.pTotal-2}
else{nums = (Math.abs(j - opts.pTotal)-3) +' - '+ ((Math.abs(j - opts.pTotal)-2));}
if(opts.covers){
if(i==opts.pTotal-2){nums=''}
else if(i==0){nums=''}
else{nums = (Math.abs(j - opts.pTotal)-5) +' - '+ ((Math.abs(j - opts.pTotal)-4));}
}
}
dd.find('.b-current').text(nums);
ddLI = $(''+ titles[i+1] +''+ nums +'').prependTo(ddUL);
}else{
if(i==0){dd.find('.b-current').text(nums);}
ddLI = $(''+ titles[i] +''+ nums +'').appendTo(ddUL);
}
ddA = ddLI.find('a');
if(!opts.hash){
ddA.click(function(){
if(opts.direction == 'RTL'){dd.find('.b-current').text($(this).find('.b-num').text());}
ddT = parseInt($(this).attr('id').replace('selector-page-',''));
self.gotoPage(ddT);
return false;
});
}
}
//set height
ddH = ddUL.height();
ddUL.css({'height':0, 'padding-bottom':0});
//add hover effects
dd.unbind('hover').hover(function(){
ddUL.stop().animate({height:ddH, paddingBottom:10}, 500);
},function(){
ddUL.stop().animate({height:0, paddingBottom:0}, 500);
});
}
//setup chapter selctor
if(opts.chapterSelector){
chapter = chapters[opts.curr];
if(chapter == ""){ chapter = chapters[opts.curr+1]; }
ddC = $(''+chapter+'
').appendTo(menu);
ddCUL = $('').appendTo(ddC).empty().css('height','auto');
for(i=0; i < opts.pTotal; i+=1){
if(chapters[i] != "" && typeof chapters[i] != "undefined"){
if(opts.direction == 'RTL'){
j = i;
if(j % 2 != 0){j--;}
ddC.find('.b-current').text(chapters[i]);
ddCLI = $(''+ chapters[i] +'').prependTo(ddCUL);
}else{
ddCLI = $(''+ chapters[i] +'').appendTo(ddCUL);
}
ddCA = ddCLI.find('a');
if(!opts.hash){
ddCA.click(function(){
if(opts.direction == 'RTL'){ddC.find('.b-current').text($(this).find('.b-text').text());}
ddCT = parseInt($(this).attr('id').replace('selector-page-',''));
self.gotoPage(ddCT);
return false;
});
}
}
}
ddCH = ddCUL.height();
ddCUL.css({'height':0, 'padding-bottom':0});
ddC.unbind('hover').hover(function(){
ddCUL.stop().animate({height:ddCH, paddingBottom:10}, 500);
},function(){
ddCUL.stop().animate({height:0, paddingBottom:0}, 500);
});
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// API METHODS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
$.extend(self,
{
next : function(){
if(!busy){
self.gotoPage(opts.curr+2);
}
},
prev : function(){
if(!busy){
self.gotoPage(opts.curr-2);
}
},
gotoPage : function(num){
//moving forward (increasing number)
if(num > opts.curr && num < opts.pTotal && num >= 0 && !busy){
busy = true;
diff = num - opts.curr;
opts.curr = num;
opts.before.call(self, opts);
updatePager();
updateCtrls();
updateHash(opts.curr+1, opts);
initAnim(diff, true, sF);
//hide p2 as p3 moves across it
if(opts.closed && opts.autoCenter && num-diff == 0){
p2.stop().animate({width:0, left:opts.pWidth}, opts.speed, opts.easing);
p4.stop().animate({left:opts.pWidth}, opts.speed, opts.easing);
}else{
p2.stop().animate({width:0}, opts.speedH, opts.easeIn);
}
//animate p3 from right to left (left: movement, width: reveal slide, paddingLeft: shadow underneath)
//call setuppages at end of animation to reset pages
//animation if dragging forward
if(p3drag){
p3.stop().animate({left:opts.pWidth/4, width:opts.pWidth*.75, paddingLeft: opts.shadowBtmWidth}, opts.speedH, opts.easeIn)
.animate({left:0, width:opts.pWidth, paddingLeft:0}, opts.speedH);
}else{
p3.stop().animate({left:opts.pWidthH, width:opts.pWidthH, paddingLeft: opts.shadowBtmWidth}, opts.speedH, opts.easeIn)
.animate({left:0, width:opts.pWidth, paddingLeft:0}, opts.speedH);
}
p3wrap.animate({left:opts.shadowBtmWidth}, opts.speedH, opts.easeIn)
.animate({left:0}, opts.speedH, opts.easeOut, function(){updateAfter()});
//moving backward (decreasing number)
}else if(num < opts.curr && num < opts.pTotal && num >= 0 && !busy){
busy = true;
diff = opts.curr - num;
opts.curr = num;
opts.before.call(self, opts);
updatePager();
updateCtrls();
updateHash(opts.curr+1, opts);
initAnim(diff, false, sB);
//animation if dragging backwards
if(p0drag){
//hide p1 as p0 moves across it
p1.animate({left:opts.pWidth, width:0}, opts.speed, opts.easing);
p1wrap.animate({left:opts.pWidthN}, opts.speed, opts.easing);
//animate p0 from left to right (right: movement, width: reveal slide, paddingLeft: shadow underneath)
if(opts.closed && opts.autoCenter && opts.curr == 0){
p0.animate({left:opts.pWidthH, width:opts.pWidthH}, opts.speedH, opts.easeIn)
.animate({left:0, width:opts.pWidth}, opts.speedH, opts.easeOut);
p2.stop().animate({left:0}, opts.speed, opts.easing);
}else{
p0.animate({left:opts.pWidth, width:opts.pWidth}, opts.speed, opts.easing);
}
//animate .wrapper content with p0 to keep content right aligned throughout
//call setuppages at end of animation to reset pages
p0wrap.animate({right:0}, opts.speed, opts.easing, function(){updateAfter()});
}else{
//hide p1 as p0 moves across it
p1.animate({left:opts.pWidth, width:0}, opts.speed, opts.easing);
p1wrap.animate({left:opts.pWidthN}, opts.speed, opts.easing);
//animate p0 from left to right (right: movement, width: reveal slide, paddingLeft: shadow underneath)
if(opts.closed && opts.autoCenter && opts.curr == 0){
p0.animate({left:opts.pWidthH, width:opts.pWidthH}, opts.speedH, opts.easeIn)
.animate({left:0, width:opts.pWidth}, opts.speedH, opts.easeOut);
p2.stop().animate({left:0}, opts.speed, opts.easing);
}else{
p0.animate({left:opts.pWidthH, width:opts.pWidthH}, opts.speedH, opts.easeIn)
.animate({left:opts.pWidth, width:opts.pWidth}, opts.speedH, opts.easeOut);
}
//animate .wrapper content with p0 to keep content right aligned throughout
//call setuppages at end of animation to reset pages
p0wrap.animate({right:opts.shadowBtmWidth}, opts.speedH,opts. easeIn)
.animate({right:0}, opts.speedH, opts.easeOut, function(){updateAfter()});
}
}
}
});
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SETUP CONTROLS
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(opts.manual && $.ui){
opts.overlays = false;
}
//add prev next user defined controls
if(opts.next){
next = $(opts.next);
next.click(function(e){e.preventDefault(); self.next();});
}
if(opts.prev){
prev = $(opts.prev);
prev.click(function(e){e.preventDefault(); self.prev();});
}
//add overlays
if(opts.overlays){
overlayP = $('').appendTo(b);
overlayN = $('').appendTo(b);
overlaysB = b.find('.b-overlay');
if ($.browser.msie) {
overlaysB.css({'background':'#fff','filter':'progid:DXImageTransform.Microsoft.Alpha(opacity=0) !important'});
}
}
//add tabs
if(opts.tabs){
tabP = $('Previous
').appendTo(b);
tabN = $('Next
').appendTo(b);
tabs = b.find('.b-tab');
if(opts.tabWidth){
tabs.width(opts.tabWidth);
}
if(opts.tabHeight){
tabs.height(opts.tabHeight);
}
tabs.css({'top': '-'+tabN.outerHeight()+'px'});
b.css({'marginTop': tabN.outerHeight()});
//update ctrls for RTL direction
if(opts.direction == 'RTL'){
tabN.html('Previous').attr('title','Previous Page');
tabP.html('Next').attr('title','Next Page');
}
}else{
b.css({'marginTop': 0});
}
//add arrows
if(opts.arrows){
arrowP = $('').appendTo(b);
arrowN = $('').appendTo(b);
arrows = b.find('.b-arrow');
//update ctrls for RTL direction
if(opts.direction == 'RTL'){
arrowN.html('Previous
').attr('title','Previous Page');
arrowP.html('Next
').attr('title','Next Page');
}
}
//save all "b-prev" and "b-next" controls
ctrlsN = b.find('.b-next');
ctrlsP = b.find('.b-prev');
//add click actions
ctrlsN.click(function(e){e.preventDefault(); self.next();});
ctrlsP.click(function(e){e.preventDefault(); self.prev();});
//add page hover animations
if(opts.overlays && opts.hovers){
//hovers to start draggable forward
ctrlsN.unbind("mouseover mouseout").bind("mouseover",function(){
hoverAnimStart(true);
})
.bind("mouseout",function(){
hoverAnimEnd(true);
});
//hovers to start draggable backwards
ctrlsP.unbind("mouseover mouseout").bind("mouseover",function(){
hoverAnimStart(false);
})
.bind("mouseout",function(){
hoverAnimEnd(false);
});
}
//arrow animations
if(opts.arrows){
if(opts.arrowsHide){
if($.support.opacity){
ctrlsN.hover(
function(){arrowN.find('div').stop().fadeTo('fast', 1);},
function(){arrowN.find('div').stop().fadeTo('fast', 0);
});
ctrlsP.hover(
function(){arrowP.find('div').stop().fadeTo('fast', 1);},
function(){arrowP.find('div').stop().fadeTo('fast', 0);
});
}else{
ctrlsN.hover(
function(){arrowN.find('div').show();},
function(){arrowN.find('div').hide();
});
ctrlsP.hover(
function(){arrowP.find('div').show();},
function(){arrowP.find('div').hide();
});
}
}else{
arrowN.find('div').show();
arrowP.find('div').show();
}
}
//keyboard ctrls
if(opts.keyboard){
//keyboard ctrls
$(document).keyup(function(event){
if(event.keyCode == 37){self.prev();}
else if(event.keyCode == 39){self.next();}
});
}
//hash ctrls
if(opts.hash){
setupHash();
clearInterval(h);
h = setInterval(function(){pollHash()}, 250);
}
//percentage resizing
if(opts.wPercent || opts.hPercent){
$(window).resize(function() {
resetSize();
});
}
//auto flip book controls
if(opts.auto && opts.delay){
clearTimeout(a);
a = setTimeout(function(){self.next();},opts.delay);
playing = true;
if(opts.pause){
pause = $(opts.pause);
pause.click(function(e){
e.preventDefault();
if(playing){
clearTimeout(a);
playing = false;
}
});
}
if(opts.play){
play = $(opts.play);
play.click(function(e){
e.preventDefault();
if(!playing){
clearTimeout(a);
a = setTimeout(function(){self.next();},opts.delay);
playing = true;
}
});
}
}
//first time setup
resetPages();
updateCtrls();
updatePager();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//General Functions
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function initPages(){
//fix for odd number of pages
if((src.children().length % 2) != 0){
//if book is closed and using covers, add page before back cover, else after last page
if(opts.closed && opts.covers){
src.children().last().before(blank);
}else{
src.children().last().after(blank);
}
}
//if closed book, add empty pages to start and end
if(opts.closed){
$(empty).attr({'title':opts.closedFrontTitle || "Beginning", 'rel':opts.closedFrontChapter || "Beginning of Book"}).prependTo(src);
src.children().last().attr({'title':opts.closedBackTitle || "End", 'rel':opts.closedBackChapter || "End of Book"});
src.append(empty);
}
if(opts.direction == 'LTR'){
j = 0;
}else{
j = src.children().length;
if(opts.closed){j-=2;}
if(opts.covers){j-=2;}
$(src.children().get().reverse()).each(function(){
$(this).appendTo(src);
});
}
//save titles and chapters
src.children().each(function(i){
//save chapter title
if($(this).attr('rel')){
chapters[i] = $(this).attr('rel');
}else{
chapters[i] = "";
}
//save page title
titles[i] = $(this).attr('title');
//give content the correct wrapper and page wrapper
if($(this).hasClass('b-page-empty')){
$(this).wrap('');
}else if(opts.closed && opts.covers && (i == 1 || i == src.children().length-2)){
$(this).wrap('');
}else if(i % 2 != 0){
$(this).wrap('');
}else{
$(this).wrap('');
}
$(this).parents('.b-page').addClass('b-page-'+i).data('page',i);
//add page numbers
if(opts.pageNumbers && !$(this).hasClass('b-page-empty') && (!opts.closed || (opts.closed && !opts.covers) || (opts.closed && opts.covers && i != 1 && i != src.children().length-2))){
if(opts.direction == 'LTR'){j++;}
$(this).parent().append(''+(j)+'
');
if(opts.direction == 'RTL'){j--;}
}
});
}
function resetSize(){
//recalculate size for percentage values
if(opts.wPercent){
opts.width = (opts.wOrig.replace('%','')/100) * parseFloat(b.parent().css('width'));
b.width(opts.width);
opts.pWidth = opts.width/2;
opts.pWidthN = '-'+(opts.pWidth)+'px';
opts.pWidthH = opts.pWidth/2;
}
if(opts.hPercent){
opts.height = (opts.hOrig.replace('%','')/100) * parseFloat(b.parent().css('height'));
b.height(opts.height);
opts.pHeight = opts.height;
}
resetCSS();
}
function resetCSS(){
//update css
b.find('.b-shadow-f, .b-shadow-b, .b-p0, .b-p3').css({'filter':'','zoom':''});
if(opts.manual && $.ui){
b.find('.b-page').draggable('destroy').removeClass('b-grab b-grabbing');
}
wraps.attr('style','');
wraps.css({'left':0,'width':opts.pWidth-(opts.pagePadding*2), 'height':opts.pHeight-(opts.pagePadding*2), 'padding': opts.pagePadding});
p0wrap.css({'right':0,'left':'auto'});
p1.css({'left':0,'width':opts.pWidth, 'height':opts.pHeight});
p2.css({'left':opts.pWidth, 'width':opts.pWidth, 'opacity':1, 'height':opts.pHeight});
pN.css({'left':0, 'width':opts.pWidth, 'height':opts.pHeight});
p0.css({'left':0, 'width':0, 'height':opts.pHeight});
p3.stop().css({'left':opts.pWidth*2, 'width':0, 'height':opts.pHeight, paddingLeft:0});
p4.css({'left':opts.pWidth, 'width':opts.pWidth, 'height':opts.pHeight});
if(opts.closed && opts.autoCenter && opts.curr == 0){
pN.css({'left':0});
p1.css({'left':opts.pWidthN});
p2.css({'left':0});
p3.css({'left':opts.pWidth});
p4.css({'left':0});
}
if(opts.closed && opts.autoCenter && (opts.curr == 0 || opts.curr >= opts.pTotal-2)){
if(opts.overlays){overlaysB.width('100%');}
b.width(opts.pWidth);
}else{
if(opts.overlays){overlaysB.width('50%');}
b.width(opts.width);
}
}
function resetPages(){
//reset page order
if(init){
if(p1.data('page')-1 < 0){
src.prepend(p2.detach());
src.prepend(p1.detach());
}else{
b.find('.b-page-'+(p1.data('page')-1)).after(p1.detach());
b.find('.b-page-'+(p2.data('page')-1)).after(p2.detach());
}
if(p3.data('page')-1 <= opts.pTotal){
b.find('.b-page-'+(p3.data('page')-1)).after(p3.detach());
b.find('.b-page-'+(p4.data('page')-1)).after(p4.detach());
}
if(pN.data('page')-1 >= 0){
b.find('.b-page-'+(pN.data('page')-1)).after(pN.detach());
b.find('.b-page-'+(p0.data('page')-1)).after(p0.detach());
}else{
src.prepend(pN.detach());
pN.after(p0.detach());
}
}
//reset all content
b.find('.b-page').removeClass('b-pN b-p0 b-p1 b-p2 b-p3 b-p4').hide();
//add page classes
if(opts.curr-2 >= 0){
b.find('.b-page-'+(opts.curr-2)).addClass('b-pN').show();
b.find('.b-page-'+(opts.curr-1)).addClass('b-p0').show();
}
b.find('.b-page-'+(opts.curr)).addClass('b-p1').show();
b.find('.b-page-'+(opts.curr+1)).addClass('b-p2').show();
if(opts.curr+3 <= opts.pTotal){
b.find('.b-page-'+(opts.curr+2)).addClass('b-p3').show();
b.find('.b-page-'+(opts.curr+3)).addClass('b-p4').show();
}
//save structure elems to vars
pN = b.find('.b-pN');
p0 = b.find('.b-p0');
p1 = b.find('.b-p1');
p2 = b.find('.b-p2');
p3 = b.find('.b-p3');
p4 = b.find('.b-p4');
pNwrap = b.find('.b-pN .b-wrap');
p0wrap = b.find('.b-p0 .b-wrap');
p1wrap = b.find('.b-p1 .b-wrap');
p2wrap = b.find('.b-p2 .b-wrap');
p3wrap = b.find('.b-p3 .b-wrap');
p4wrap = b.find('.b-p4 .b-wrap');
wraps = b.find('.b-wrap');
resetCSS();
//update page order for animations
if(opts.curr+3 <= opts.pTotal){
p3.after(p0.detach());
p1.after(p4.detach());
}else{
p0.detach().appendTo(src);
}
init = true;
if(opts.shadows){
b.find('.b-shadow-f, .b-shadow-b').remove();
sF = $('').css({'right':0,'width':opts.pWidth, 'height':opts.pHeight}).appendTo(p3);
sB = $('').appendTo(p0).css({'left':0,'width':opts.pWidth, 'height':opts.pHeight});
}
//reset vars
rhover = lhover = p3drag = p0drag = false;
//manual page turning, check if jQuery UI is loaded
if(opts.manual && $.ui){
//implement draggable forward
p3.draggable({
axis: "x",
containment: [p2.offset().left-opts.pWidthH,0,p2.offset().left+opts.pWidth-50,opts.pHeight],
drag: function(event, ui) {
p3drag = true;
temp = ui.originalPosition.left - ui.position.left;
p3.removeClass('b-grab').addClass('b-grabbing');
p3.width(40+(temp/2));
p3wrap.css({'left':10+(temp/8)});
p2.width(opts.pWidth-p3.width()+10);
if(opts.shadows){
sF.css({'right':'-'+(20+temp/4)+'px'});
if($.support.opacity){
sF.css({'opacity':0.5*(temp/opts.pWidthH)});
}else{
sF.css({'right':'auto','left':0.1*p3.width()});
}
}
},
stop: function(event, ui) {
hoverAnimEnd(false);
var temp = ui.originalPosition.left - ui.position.left;
if(temp>opts.pWidthH/4){
if(opts.shadows && !$.support.opacity){
sF.css({'left':'auto'});
}
self.next();
p3.removeClass('b-grab b-grabbing');
}else{
p3drag = false;
p3.removeClass('b-grabbing').addClass('b-grab');
}
}
});
//implement draggable backwards
p0.draggable({
axis: "x",
containment: [p1.offset().left+10,0,p1.offset().left+opts.pWidth*.75,opts.pHeight],
drag: function(event, ui) {
p0drag = true;
temp = ui.position.left - ui.originalPosition.left;
p0.removeClass('b-grab').addClass('b-grabbing');
p0.css({left:40+(temp)/1.5, width:40+(temp)});
p0wrap.css({right:10+temp/4});
p1.css({left:ui.position.left+20, width:opts.pWidth-ui.position.left-10});
p1wrap.css({left:-1*(temp+30)});
if(opts.shadows){
if($.support.opacity){
sB.css({'opacity':0.5*(temp/opts.pWidthH)});
}else{
sB.css({'left':-0.38*opts.pWidth});
}
}
},
stop: function(event, ui) {
hoverAnimEnd(true);
temp = ui.position.left - ui.originalPosition.left;
if(temp>opts.pWidthH/4){
self.prev();
p0.removeClass('b-grab b-grabbing');
}else{
p0drag = false;
p0.removeClass('b-grabbing').addClass('b-grab');
}
}
});
//mousetracking for page movement
$(b).unbind('mousemove mouseout').bind('mousemove',function(e){
relativeX = e.pageX - b.offset().left;
if(relativeX < 50){
hoverAnimStart(false);
}else if(relativeX > opts.pWidth-50 && opts.curr == 0 && opts.autoCenter && opts.closed){
hoverAnimStart(true);
}else if(relativeX > 50 && relativeX < opts.width-50){
hoverAnimEnd(false);
hoverAnimEnd(true);
}else if(relativeX > opts.width-50){
hoverAnimStart(true);
}
}).bind('mouseout',function(){
hoverAnimEnd(false);
hoverAnimEnd(true);
});
}
}
function hoverAnimStart(inc){
if(inc){
if(!busy && !rhover &&!lhover && !p3drag && opts.curr+2 <= opts.pTotal-2){
//animate
p2.stop().animate({'width':opts.pWidth-40}, 500, opts.easing);
p3.addClass('b-grab');
if(opts.closed && opts.autoCenter && opts.curr == 0){
p3.stop().animate({'left':opts.pWidth-50, 'width':40}, 500, opts.easing);
}else{
p3.stop().animate({'left':opts.width-50, 'width':40}, 500, opts.easing);
}
p3wrap.stop().animate({'left':10}, 500, opts.easing);
if(opts.shadows && !$.support.opacity){
sF.css({'right':'auto','left':'-40%'});
}
rhover = true;
}
}else{
if(!busy && !lhover && !rhover && !p0drag && opts.curr-2 >= 0){
//animate
p1.stop().animate({left:10, width:opts.pWidth-10}, 400, opts.easing);
p0.addClass('b-grab');
p1wrap.stop().animate({left:"-10px"}, 400, opts.easing);
p0.stop().animate({left:10, width:40}, 400, opts.easing);
p0wrap.stop().animate({right:10}, 400, opts.easing);
if(opts.shadows && !$.support.opacity){
sB.css({'left':-0.38*opts.pWidth});
}
lhover = true;
}
}
}
function hoverAnimEnd(inc){
if(inc){
if(!busy && rhover && !p3drag && opts.curr+2 <= opts.pTotal-2){
p2.stop().animate({'width':opts.pWidth}, 500, opts.easing);
if(opts.closed && opts.autoCenter && opts.curr == 0){
p3.stop().animate({'left':opts.pWidth, 'width':0}, 500, opts.easing);
}else{
p3.stop().animate({'left':opts.width, 'width':0}, 500, opts.easing);
}
p3wrap.stop().animate({'left':0}, 500, opts.easing);
if(opts.shadows && !$.support.opacity){
sF.css({'left':'auto'});
}
rhover = false;
}
}else{
if(!busy && lhover && !p0drag && opts.curr-2 >= 0){
p1.stop().animate({left:0, width:opts.pWidth}, 400, opts.easing);
p1wrap.stop().animate({left:0}, 400, opts.easing);
p0.stop().animate({left:0, width:0}, 400, opts.easing);
p0wrap.stop().animate({right:0}, 400, opts.easing);
lhover = false;
}
}
}
function initAnim(diff, inc, shadow){
//setup content
if(inc && diff > 2){
b.find('.b-page-'+(p3.data('page')-1)).after(p3.detach());
b.find('.b-page-'+(p4.data('page')-1)).after(p4.detach());
b.find('.b-p3, .b-p4').removeClass('b-p3 b-p4').hide();
b.find('.b-page-'+opts.curr).addClass('b-p3').show().stop().css({'left':opts.pWidth*2, 'width':0, 'height':opts.pHeight, paddingLeft:0});
b.find('.b-page-'+(opts.curr+1)).addClass('b-p4').show().css({'left':opts.pWidth, 'width':opts.pWidth, 'height':opts.pHeight});
b.find('.b-page-'+opts.curr+' .b-wrap').show().css({'width':opts.pWidth-(opts.pagePadding*2), 'height':opts.pHeight-(opts.pagePadding*2), 'padding': opts.pagePadding});
b.find('.b-page-'+(opts.curr+1)+' .b-wrap').show().css({'width':opts.pWidth-(opts.pagePadding*2), 'height':opts.pHeight-(opts.pagePadding*2), 'padding': opts.pagePadding});
p3 = b.find('.b-p3');
p4 = b.find('.b-p4');
p3wrap = b.find('.b-p3 .b-wrap');
p4wrap = b.find('.b-p4 .b-wrap');
if(rhover){
p3.css({'left':opts.width-40, 'width':20, 'padding-left': 10});
}
p1.after(p4.detach());
p2.after(p3.detach());
if (opts.shadows) {
b.find('.b-shadow-f').remove();
sF = $('').css({
'right': 0,
'width': opts.pWidth,
'height': opts.pHeight
}).appendTo(p3);
shadow = sF;
}
}else if(!inc && diff > 2){
b.find('.b-page-'+(pN.data('page')-1)).after(pN.detach());
b.find('.b-page-'+(p0.data('page')-1)).after(p0.detach());
b.find('.b-pN, .b-p0').removeClass('b-pN b-p0').hide();
b.find('.b-page-'+opts.curr).addClass('b-pN').show().css({'left':0, 'width':opts.pWidth, 'height':opts.pHeight});
b.find('.b-page-'+(opts.curr+1)).addClass('b-p0').show().css({'left':0, 'width':0, 'height':opts.pHeight});
b.find('.b-page-'+opts.curr+' .b-wrap').show().css({'width':opts.pWidth-(opts.pagePadding*2), 'height':opts.pHeight-(opts.pagePadding*2), 'padding': opts.pagePadding});
b.find('.b-page-'+(opts.curr+1)+' .b-wrap').show().css({'width':opts.pWidth-(opts.pagePadding*2), 'height':opts.pHeight-(opts.pagePadding*2), 'padding': opts.pagePadding});
pN = b.find('.b-pN');
p0 = b.find('.b-p0');
pNwrap = b.find('.b-pN .b-wrap');
p0wrap = b.find('.b-p0 .b-wrap');
if(lhover){
p0.css({left:10, width:40});
p0wrap.css({right:10});
}
p0.detach().appendTo(src);
if (opts.shadows) {
b.find('.b-shadow-b, .b-shadow-f').remove();
sB = $('').appendTo(p0).css({
'left': 0,
'width': opts.pWidth,
'height': opts.pHeight
});
shadow = sB;
}
}
//update page visibility
//if moving to start and end of book
if(opts.closed){
if(!inc && opts.curr == 0){
pN.hide();
}else if(!inc){
pN.show();
}
if(inc && opts.curr >= opts.pTotal-2){
p4.hide();
}else if(inc){
p4.show();
}
}
//init shadows
if(opts.shadows){
//check for opacity support -> animate shadow overlay on moving slide
if($.support.opacity){
shadow.animate({opacity:1}, opts.speedH, opts.easeIn)
.animate({opacity:0}, opts.speedH, opts.easeOut);
}else{
if(inc){
shadow.animate({right:opts.shadowTopFwdWidth}, opts.speed, opts.easeIn);
}else{
shadow.animate({left:opts.shadowTopBackWidth}, opts.speed, opts.easeIn);
}
}
}
//init position anim
if(opts.closed && opts.autoCenter){
if(opts.curr == 0){
p3.hide();
p4.hide();
b.animate({width:opts.pWidth}, opts.speed, opts.easing);
}else if(opts.curr >= opts.pTotal-2){
p0.hide();
pN.hide();
b.animate({width:opts.pWidth}, opts.speed, opts.easing);
}else{
b.animate({width:opts.width}, opts.speed, opts.easing);
}
}
}
function updateAfter(){
resetPages();
updatePager();
updateCtrls();
opts.after.call(self, opts);
busy = false;
//update auto play timer
if(opts.auto && opts.delay){
if(playing && opts.curr < opts.pTotal-2){
clearTimeout(a);
a = setTimeout(function(){self.next();},opts.delay);
console.log("continue...");
}
if(opts.curr >= opts.pTotal-2){
playing = false;
}
}
}
function updateCtrls(){
//update ctrls, cursors and visibility
if(opts.overlays || opts.tabs || opts.arrows){
if($.support.opacity){
if(opts.curr < opts.pTotal-2){
ctrlsN.fadeIn('fast').css('cursor',opts.cursor);
}else{
ctrlsN.fadeOut('fast').css('cursor','default');
}
if(opts.curr >= 2 && opts.curr != 0){
ctrlsP.fadeIn('fast').css('cursor',opts.cursor);
}else{
ctrlsP.fadeOut('fast').css('cursor','default');
}
}else{
if(opts.curr < opts.pTotal-2){
ctrlsN.show().css('cursor',opts.cursor);
}else{
ctrlsN.hide().css('cursor','default');
}
if(opts.curr >= 2 && opts.curr != 0){
ctrlsP.show().css('cursor',opts.cursor);
}else{
ctrlsP.hide().css('cursor','default');
}
}
}
}
function updatePager(){
if(opts.pageSelector){
if(opts.direction == 'RTL'){
nums = (Math.abs(opts.curr - opts.pTotal)-1) +' - '+ ((Math.abs(opts.curr - opts.pTotal)));
if(opts.closed){
if(opts.curr==opts.pTotal-2){nums='1'}
else if(opts.curr==0){nums=opts.pTotal-2}
else{nums = (Math.abs(opts.curr - opts.pTotal)-2) +' - '+ ((Math.abs(opts.curr - opts.pTotal)-1));}
if(opts.covers){
if(opts.curr==opts.pTotal-2){nums=''}
else if(opts.curr==0){nums=''}
else{nums = (Math.abs(opts.curr - opts.pTotal)-3) +' - '+ ((Math.abs(opts.curr - opts.pTotal)-2));}
}
}
$(opts.menu+' .b-selector-page .b-current').text(nums);
}else{
nums = (opts.curr+1) +' - '+ (opts.curr+2);
if(opts.closed){
if(opts.curr==0){nums='1'}
else if(opts.curr==opts.pTotal-2){nums=opts.pTotal-2}
else {nums = (opts.curr) +'-'+ (opts.curr+1);}
if(opts.covers){
if(opts.curr==0){nums=''}
else if(opts.curr==opts.pTotal-2){nums=''}
else {nums = (opts.curr-1) +'-'+ (opts.curr);}
}
}
$(opts.menu+' .b-selector-page .b-current').text(nums);
}
}
if(opts.chapterSelector){
if(chapters[opts.curr]!=""){
$(opts.menu+' .b-selector-chapter .b-current').text(chapters[opts.curr]);
}else if(chapters[opts.curr+1]!=""){
$(opts.menu+' .b-selector-chapter .b-current').text(chapters[opts.curr+1]);
}
if(opts.direction == 'RTL' && chapters[opts.curr+1]!=""){
$(opts.menu+' .b-selector-chapter .b-current').text(chapters[opts.curr+1]);
}else if(chapters[opts.curr]!=""){
$(opts.menu+' .b-selector-chapter .b-current').text(chapters[opts.curr]);
}
}
}
function setupHash(){
hash = getHashNum();
if(!isNaN(hash) && hash <= opts.pTotal-1 && hash >= 0 && hash != ''){
if((hash % 2) != 0){
hash--;
}
opts.curr = hash;
}else{
updateHash(opts.curr+1, opts);
}
self.hash = hash;
}
function pollHash(){
hash = getHashNum();
//check page num
if(!isNaN(hash) && hash <= opts.pTotal-1 && hash >= 0){
if(hash != opts.curr && hash.toString()!=self.hash){
if((hash % 2) != 0){hash--};
document.title = opts.name + " - Page "+ (hash+1);
if(!busy){
self.gotoPage(hash);
self.hash = hash;
}
}
}
}
//get page number from hash tag, last element
function getHashNum(){
var hash = window.location.hash.split('/');
if(hash.length > 1){
return parseInt(hash[2])-1;
}else{
return '';
}
}
//set the hash
function updateHash(hash, opts){
if(opts.hash){
window.location.hash = "/page/" + hash;
}
}
}
//define empty array to hold API references
$.fn.booklet.interfaces = [];
//define default options
$.fn.booklet.defaults = {
name: null, // name of the booklet to display in the document title bar
width: 600, // container width
height: 400, // container height
speed: 1000, // speed of the transition between pages
direction: 'LTR', // direction of the overall content organization, default LTR, left to right, can be RTL for languages which read right to left
startingPage: 0, // index of the first page to be displayed
easing: 'easeInOutQuad', // easing method for complete transition
easeIn: 'easeInQuad', // easing method for first half of transition
easeOut: 'easeOutQuad', // easing method for second half of transition
closed: false, // start with the book "closed", will add empty pages to beginning and end of book
closedFrontTitle: null, // used with "closed", "menu" and "pageSelector", determines title of blank starting page
closedFrontChapter: null, // used with "closed", "menu" and "chapterSelector", determines chapter name of blank starting page
closedBackTitle: null, // used with "closed", "menu" and "pageSelector", determines chapter name of blank ending page
closedBackChapter: null, // used with "closed", "menu" and "chapterSelector", determines chapter name of blank ending page
covers: false, // used with "closed", makes first and last pages into covers, without page numbers (if enabled)
autoCenter: false, // used with "closed", makes book position in center of container when closed
pagePadding: 10, // padding for each page wrapper
pageNumbers: true, // display page numbers on each page
manual: true, // enables manual page turning, requires jQuery UI to function
hovers: true, // enables preview pageturn hover animation, shows a small preview of previous or next page on hover
overlays: true, // enables navigation using a page sized overlay, when enabled links inside the content will not be clickable
tabs: false, // adds tabs along the top of the pages
tabWidth: 60, // set the width of the tabs
tabHeight: 20, // set the height of the tabs
arrows: false, // adds arrows overlayed over the book edges
arrowsHide: false, // auto hides arrows when controls are not hovered
cursor: 'pointer', // cursor css setting for side bar areas
hash: false, // enables navigation using a hash string, ex: #/page/1 for page 1, will affect all booklets with 'hash' enabled
keyboard: true, // enables navigation with arrow keys (left: previous, right: next)
next: null, // selector for element to use as click trigger for next page
prev: null, // selector for element to use as click trigger for previous page
auto: false, // enables automatic navigation, requires "delay"
delay: 5000, // amount of time between automatic page flipping
pause: null, // selector for element to use as click trigger for pausing auto page flipping
play: null, // selector for element to use as click trigger for restarting auto page flipping
menu: null, // selector for element to use as the menu area, required for 'pageSelector'
pageSelector: false, // enables navigation with a dropdown menu of pages, requires 'menu'
chapterSelector: false, // enables navigation with a dropdown menu of chapters, determined by the "rel" attribute, requires 'menu'
shadows: true, // display shadows on page animations
shadowTopFwdWidth: 166, // shadow width for top forward anim
shadowTopBackWidth: 166, // shadow width for top back anim
shadowBtmWidth: 50, // shadow width for bottom shadow
before: function(){}, // callback invoked before each page turn animation
after: function(){} // callback invoked after each page turn animation
}
})(jQuery);