/* 08/24/2010
PikaChoose
Jquery plugin for photo galleries
Copyright (C) 2010 Jeremy Fry
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
(function($) {
/**
* Creates a slideshow for all matched elements.
*
* @example $("#pikame").PikaChoose();
* @input needed
Caption
Caption
*
* @method PikaChoose
* @return $
* @param o {Hash|String} A set of key/value pairs to set as configuration properties or a method name to call on a formerly created instance.
*/
var defaults = {
autoPlay: true,
speed: 5000,
text: {
play: "",
stop: "",
previous: "Previous",
next: "Next"
},
transition:[-1],
showCaption: false,
IESafe: false
};
$.fn.PikaChoose = function(o) {
return this.each(function() {
$(this).data('pikachoose', new $pc(this, o));
});
}
/**
* The PikaChoose object.
*
* @constructor
* @class pikachoose
* @param e {HTMLElement} The element to create the carousel for.
* @param o {Object} A set of key/value pairs to set as configuration properties.
* @cat Plugins/PikaChoose
*/
$.PikaChoose = function(e, o) {
this.options = $.extend({}, defaults, o || {});
this.list = null;
this.image = null;
this.anchor = null;
this.caption = null;
this.imgNav = null;
this.imgPlay = null;
this.imgPrev = null;
this.imgNext = null;
this.textNext = null;
this.textPrev = null;
this.previous = null;
this.next = null;
this.aniDiv = null;
this.thumbs = null;
this.transition= null;
this.active = null;
this.animating = false;
if (e.nodeName == 'UL' || e.nodeName == 'OL') {
this.list = $(e);
this.build();
this.bindEvents();
}else{
return;
}
var y = 0;
var x = 0;
for(var t = 0; t<25;t++)
{
var a = '';
this.aniDiv.append(a);
y++
if(y == 5)
{
x++;
y=0;
}
}
}//end PikaChoose function(e, o)
var $pc = $.PikaChoose;
$pc.fn = $pc.prototype = {
pikachoose: '4.0.3'
};
$pc.fn.extend = $pc.extend = $.extend;
$pc.fn.extend({
/**
* Builds the gallery structure.
*
* @method build
* @return undefined
*/
build: function() {
this.step = 0; //transition step count
//create the structure for pikachoose
this.wrap = $("").insertBefore(this.list);
this.image = $("
").appendTo(this.wrap);
this.anchor = this.image.wrap("").parent();
this.imgNav = $("").insertAfter(this.anchor);
this.imgPlay = $("").appendTo(this.imgNav);
if(this.options.autoPlay){
this.imgPlay.addClass('pause');
}else{
this.imgPlay.addClass('play');
}
this.imgPrev = $("").insertAfter(this.imgPlay);
this.imgNext = $("").insertAfter(this.imgPrev);
this.caption = $("").insertAfter(this.imgNav);
if(!this.options.showCaption){
this.caption.hide();
}
this.aniDiv = $("").insertAfter(this.caption);
this.textNav = $("").insertAfter(this.aniDiv);
this.textPrev = $(""+this.options.text.previous+"").appendTo(this.textNav);
this.textNext = $(""+this.options.text.next+"").appendTo(this.textNav);
this.list.addClass('pika-thumbs');
this.list.children('li').wrapInner("");
this.thumbs = this.list.find('img');
this.active = this.thumbs.eq(0);
//fill in info for first image
this.finishAnimating({
'source':this.active.attr('ref') || this.active.attr('src'),
'caption':this.active.parents('li:first').find('span:first').html(),
'clickThrough':this.active.parent().attr('href') || ""
});
//process all the thumbnails
this.thumbs.each(this.createThumb);
}, //end setup
/**
* proccesses thumbnails
*
* @method createThumb
* @return undefined
*/
createThumb: function() {
var self = $(this);
$(this).hide();
//store all the data with the image
$.data(this,'clickThrough',$(this).parent('a').attr('href') || "#");
if($(this).parent('a').length > 0){
$(this).unwrap();
}
$.data(this,'caption',$(this).next('span').html() || "");
$(this).next('span').remove();
$.data(this,'source',$(this).attr('ref') || $(this).attr('src'));
$.data(this,'order',$("ul li").index($(this).parents('li')));
//pass data so it can enter the load scope
var data = $.data(this);
},//end createThumb
/**
* proccesses thumbnails
*
* @method bindEvents
* @return undefined
*/
bindEvents: function() {
this.thumbs.bind('click',{
self:this
},this.imgClick);
this.imgNext.bind('click',{
self:this
},this.nextClick);
this.textNext.bind('click',{
self:this
},this.nextClick);
this.imgPrev.bind('click',{
self:this
},this.prevClick);
this.textPrev.bind('click',{
self:this
},this.prevClick);
this.imgPlay.bind('click',{
self:this
},this.playClick);
this.wrap.bind('mouseenter',{
self:this
},function(e){
e.data.self.imgPlay.stop(true,true).fadeIn('fast');
});
this.wrap.bind('mouseleave',{
self:this
},function(e){
e.data.self.imgPlay.stop(true,true).fadeOut('fast');
});
},//end bind event
/**
* handles gallery after aclick occurs. and sets active classes
*
* @method imgClick
* @return undefined
*/
imgClick: function(e,x) {
var self = e.data.self;
if(self.animating){
return;
}
self.caption.fadeOut('slow');
if(typeof(x) == 'undefined' || x.how != "auto")
{
//arrive here if natural click
if(self.options.autoPlay)
{
self.imgPlay.trigger('click');
}
}
self.animating = true;
self.active.fadeTo(300,0.4).removeClass('active');
self.active = $(this);
self.active.addClass('active').fadeTo(200,1);
var data = $.data(this);
$('
').bind('load', {
self:self,
data:data
}, function()
{
//in this scope self referes to the PikaChoose object
self.aniDiv.css({
height:self.image.innerHeight(),
width:self.image.innerWidth()
}).fadeIn('fast');
self.aniDiv.children('div').css({
'width':'20%',
'height':'20%',
'float':'left'
});
//decide our transition
var n = 0;
if(self.options.transition[0] == -1)
{ //random
n = Math.floor(Math.random()*6);
}else{
n = self.options.transition[self.step];
self.step++;
if(self.step >= self.options.transition.length){
self.step=0;
}
}
if(self.options.IESafe && $.browser.msie){
n = 0;
}
self.doAnimation(n,data);
}).attr('src',$.data(this).source);//end image preload
},//end bindEvents
doAnimation: function(n,data)
{
var self = this; //self in this scope refers to PikaChoose object. Needed for callbacks on animations
var aWidth = self.aniDiv.children('div').eq(0).innerWidth();
var aHeight = self.aniDiv.children('div').eq(0).innerHeight();
self.aniDiv.children().each(function()
{
//position myself absolutely
var div = $(this);
var xOffset = Math.floor(div.parent().innerWidth()/5)*div.attr('col');
var yOffset = Math.floor(div.parent().innerHeight()/5)*div.attr('row');
div.css({
'background':'url('+data.source+') -'+xOffset+'px -'+yOffset+'px',
'width':'0px',
'height':'0px',
'position':'absolute',
'top':yOffset+'px',
'left':xOffset+'px',
'float':'none'
});
});//end ani_divs.children.each
switch(n)
{
case 0:
//full frame fade
self.aniDiv.css('height',self.image.innerHeight() + 'px').hide().css({
'background':'url('+data.source+') top left no-repeat'
});
self.aniDiv.children('div').hide();
self.aniDiv.fadeIn('slow',function(){
self.finishAnimating(data);
self.aniDiv.css({
'background':'transparent'
});
});
break;
case 1:
self.aniDiv.children().hide().each(function(index)
{
//animate out as blocks
var delay = index*30;
$(this).css({
opacity: 0.1
}).delay(delay).animate({
opacity: 1,
"width":aWidth,
"height":aHeight
},200,'linear',function()
{
if($(".animation div").index(this) == 24)
{
self.finishAnimating(data);
}
});
});
break;
case 2:
self.aniDiv.children().hide().each(function(index)
{
var delay = $(this).attr('row')*30;
$(this).css({
opacity:0.1,
"width":aWidth
}).delay(delay).animate({
opacity:1,
"height":aHeight
},500,'linear',function()
{
if($(".animation div").index(this) == 24)
{
self.finishAnimating(data);
}
});
});
break;
case 3:
self.aniDiv.children().hide().each(function(index)
{
var delay = $(this).attr('col')*10;
aHeight = self.gapper($(this), aHeight);
$(this).css({
opacity:0.1,
"height":aHeight
}).delay(delay).animate({
opacity:1,
"width":aWidth
},800,'linear',function()
{
if($(".animation div").index(this) == 24)
{
self.finishAnimating(data);
}
});
});
break;
case 4:
self.aniDiv.children().show().each(function(index)
{
var delay = index*Math.floor(Math.random()*5)*10;
aHeight = self.gapper($(this), aHeight);
if($(".animation div").index(this) == 24)
{
delay = 800;
}
$(this).css({
"height":aHeight,
"width":aWidth,
"opacity":.01
}).delay(delay).animate({
"opacity":1
},800,function()
{
if($(".animation div").index(this) == 24)
{
self.finishAnimating(data);
}
});
});
break;
case 5:
//full frame slide
self.aniDiv.css('height',self.image.innerHeight() + 'px').hide().css({
'background':'url('+data.source+') top left no-repeat'
});
self.aniDiv.children('div').hide();
self.aniDiv.css({
width:0
}).animate({
width:self.image.innerWidth()
},'slow',function(){
self.finishAnimating(data);
self.aniDiv.css({
'background':'transparent'
});
});
break;
case 6:
//fade out then in
self.aniDiv.hide();
self.image.fadeOut('slow',function(){
self.image.attr('src',data.source).fadeIn('slow',function()
{
self.finishAnimating(data);
});
});
break;
}
},//end doAnimation
finishAnimating: function(data)
{
this.animating = false;
this.image.attr('src',data.source);
this.aniDiv.hide();
this.anchor.attr('href',data.clickThrough);
if(this.options.showCaption)
{
this.caption.html(data.caption).fadeIn('slow');
}
if(this.options.autoPlay == true)
{
var self = this;
this.image.delay(this.options.speed).fadeIn(0,function(){
if(self.options.autoPlay){
self.nextClick();
}
});
}
},//end finishedAnimating
gapper: function(ele, aHeight)
{
if(ele.attr('row') == 9 && ele.attr('col') == 0)
{
//last row, check the gap and fix it!
var gap = ani_divs.innerHeight()-(aHeight*9);
return gap;
}
return aHeight;
},
nextClick : function(e)
{
var how = "natural";
try{
var self = e.data.self;
}catch(err)
{
var self = this;
how = "auto";
}
var next = self.active.parents('li:first').next().find('img');
if(next.length == 0){
next = self.list.find('img').eq(0);
};
next.trigger('click',{
how:how
});
},
prevClick : function(e)
{
var self = e.data.self;
var prev = self.active.parents('li:first').prev().find('img');
if(prev.length == 0){
prev = self.list.find('img:last');
};
prev.trigger('click');
},
playClick: function(e)
{
var self = e.data.self;
self.options.autoPlay = !self.options.autoPlay;
self.imgPlay.toggleClass('play').toggleClass('pause');
if(self.options.autoPlay){
self.nextClick();
}
}
}); //end extend
})(jQuery);