(function($){
$.fn.jcarousel=function(o){
if(typeof o=='string'){
var instance=$(this).data('jcarousel'),args=Array.prototype.slice.call(arguments,1)
return instance[o].apply(instance,args)
}else
return this.each(function(){
$(this).data('jcarousel',new $jc(this,o))
})}
var defaults={
vertical: false,
start: 1,
offset: 1,
size: null,
scroll: 3,
visible: null,
animation: 'normal',
easing: 'swing',
auto: 0,
wrap: null,
initCallback: null,
reloadCallback: null,
itemLoadCallback: null,
itemFirstInCallback: null,
itemFirstOutCallback: null,
itemLastInCallback: null,
itemLastOutCallback: null,
itemVisibleInCallback: null,
itemVisibleOutCallback: null,
buttonNextHTML: '<div></div>',
buttonPrevHTML: '<div></div>',
buttonNextEvent: 'click',
buttonPrevEvent: 'click',
buttonNextCallback: null,
buttonPrevCallback: null}
$.jcarousel=function(e,o){
this.options=$.extend({},defaults,o ||{})
this.locked=false
this.container=null
this.clip=null
this.list=null
this.buttonNext=null
this.buttonPrev=null
this.wh=!this.options.vertical ? 'width' : 'height'
this.lt=!this.options.vertical ? 'left' : 'top'
var skin='',split=e.className.split(' ')
for(var i=0;i<split.length;i++){
if(split[i].indexOf('jcarousel-skin')!=-1){
$(e).removeClass(split[i])
skin=split[i]
break}}
if(e.nodeName=='UL' || e.nodeName=='OL'){
this.list=$(e)
this.container=this.list.parent()
if(this.container.hasClass('jcarousel-clip')){
if(!this.container.parent().hasClass('jcarousel-container'))
this.container=this.container.wrap('<div></div>')
this.container=this.container.parent()
}else if(!this.container.hasClass('jcarousel-container'))
this.container=this.list.wrap('<div></div>').parent()
}else{
this.container=$(e)
this.list=this.container.find('ul,ol').eq(0)}
if(skin !=''&&this.container.parent()[0].className.indexOf('jcarousel-skin')==-1)
this.container.wrap('<div class=" '+skin+'"></div>')
this.clip=this.list.parent()
if(!this.clip.length || !this.clip.hasClass('jcarousel-clip'))
this.clip=this.list.wrap('<div></div>').parent()
this.buttonNext=$('.jcarousel-next',this.container)
if(this.buttonNext.size()==0&&this.options.buttonNextHTML !=null)
this.buttonNext=this.clip.after(this.options.buttonNextHTML).next()
this.buttonNext.addClass(this.className('jcarousel-next'))
this.buttonPrev=$('.jcarousel-prev',this.container)
if(this.buttonPrev.size()==0&&this.options.buttonPrevHTML !=null)
this.buttonPrev=this.clip.after(this.options.buttonPrevHTML).next()
this.buttonPrev.addClass(this.className('jcarousel-prev'))
this.clip.addClass(this.className('jcarousel-clip')).css({
overflow: 'hidden',
position: 'relative'
})
this.list.addClass(this.className('jcarousel-list')).css({
overflow: 'hidden',
position: 'relative',
top: 0,
left: 0,
margin: 0,
padding: 0
})
this.container.addClass(this.className('jcarousel-container')).css({
position: 'relative'
})
var di=this.options.visible !=null ? Math.ceil(this.clipping()/this.options.visible): null
var li=this.list.children('li')
var self=this
if(li.size()>0){
var wh=0,i=this.options.offset
li.each(function(){
self.format(this,i++)
wh+=self.dimension(this,di)
})
this.list.css(this.wh,wh+'px')
if(!o || o.size===undefined)
this.options.size=li.size()}
this.container.css('display','block')
this.buttonNext.css('display','block')
this.buttonPrev.css('display','block')
this.funcNext=function(){self.next();}
this.funcPrev=function(){self.prev();}
this.funcResize=function(){self.reload();}
if(this.options.initCallback !=null)
this.options.initCallback(this,'init')
if($.browser.safari){
this.buttons(false,false)
$(window).bind('load.jcarousel',function(){self.setup();})
}else
this.setup()}
var $jc=$.jcarousel
$jc.fn=$jc.prototype={
jcarousel: '0.2.4'}
$jc.fn.extend=$jc.extend=$.extend
$jc.fn.extend({
setup: function(){
this.first=null
this.last=null
this.prevFirst=null
this.prevLast=null
this.animating=false
this.timer=null
this.tail=null
this.inTail=false
if(this.locked)
return
this.list.css(this.lt,this.pos(this.options.offset)+'px')
var p=this.pos(this.options.start)
this.prevFirst=this.prevLast=null
this.animate(p,false)
$(window).unbind('resize.jcarousel',this.funcResize).bind('resize.jcarousel',this.funcResize)
},
reset: function(){
this.list.empty()
this.list.css(this.lt,'0px')
this.list.css(this.wh,'10px')
if(this.options.initCallback !=null)
this.options.initCallback(this,'reset')
this.setup()
},
reload: function(){
if(this.tail !=null&&this.inTail)
this.list.css(this.lt,$jc.intval(this.list.css(this.lt))+this.tail)
this.tail=null
this.inTail=false
if(this.options.reloadCallback !=null)
this.options.reloadCallback(this)
if(this.options.visible !=null){
var self=this
var di=Math.ceil(this.clipping()/this.options.visible),wh=0,lt=0
$('li',this.list).each(function(i){
wh+=self.dimension(this,di)
if(i+1<self.first)
lt=wh
})
this.list.css(this.wh,wh+'px')
this.list.css(this.lt,-lt+'px')}
this.scroll(this.first,false)
},
lock: function(){
this.locked=true
this.buttons()
},
unlock: function(){
this.locked=false
this.buttons()
},
size: function(s){
if(s !=undefined){
this.options.size=s
if(!this.locked)
this.buttons()}
return this.options.size
},
has: function(i,i2){
if(i2==undefined || !i2)
i2=i
if(this.options.size !==null&&i2>this.options.size)
i2=this.options.size
for(var j=i;j<=i2;j++){
var e=this.get(j)
if(!e.length || e.hasClass('jcarousel-item-placeholder'))
return false}
return true
},
get: function(i){
return $('.jcarousel-item-'+i,this.list)
},
add: function(i,s){
var e=this.get(i),old=0,add=0
if(e.length==0){
var c,e=this.create(i),j=$jc.intval(i)
while(c=this.get(--j)){
if(j<=0 || c.length){
j<=0 ? this.list.prepend(e): c.after(e)
break}}
}else
old=this.dimension(e)
e.removeClass(this.className('jcarousel-item-placeholder'))
typeof s=='string' ? e.html(s): e.empty().append(s)
var di=this.options.visible !=null ? Math.ceil(this.clipping()/this.options.visible): null
var wh=this.dimension(e,di)-old
if(i>0&&i<this.first)
this.list.css(this.lt,$jc.intval(this.list.css(this.lt))-wh+'px')
this.list.css(this.wh,$jc.intval(this.list.css(this.wh))+wh+'px')
return e
},
remove: function(i){
var e=this.get(i)
if(!e.length ||(i>=this.first&&i<=this.last))
return
var d=this.dimension(e)
if(i<this.first)
this.list.css(this.lt,$jc.intval(this.list.css(this.lt))+d+'px')
e.remove()
this.list.css(this.wh,$jc.intval(this.list.css(this.wh))-d+'px')
},
next: function(){
this.stopAuto()
if(this.tail !=null&&!this.inTail)
this.scrollTail(false)
else
this.scroll(((this.options.wrap=='both' || this.options.wrap=='last')&&this.options.size !=null&&this.last==this.options.size)? 1 : this.first+this.options.scroll)
},
prev: function(){
this.stopAuto()
if(this.tail !=null&&this.inTail)
this.scrollTail(true)
else
this.scroll(((this.options.wrap=='both' || this.options.wrap=='first')&&this.options.size !=null&&this.first==1)? this.options.size : this.first-this.options.scroll)
},
scrollTail: function(b){
if(this.locked || this.animating || !this.tail)
return
var pos=$jc.intval(this.list.css(this.lt))
!b ? pos-=this.tail : pos+=this.tail
this.inTail=!b
this.prevFirst=this.first
this.prevLast=this.last
this.animate(pos)
},
scroll: function(i,a){
if(this.locked || this.animating)
return
this.animate(this.pos(i),a)
},
pos: function(i){
var pos=$jc.intval(this.list.css(this.lt))
if(this.locked || this.animating)
return pos
if(this.options.wrap !='circular')
i=i<1 ? 1 :(this.options.size&&i>this.options.size ? this.options.size : i)
var back=this.first>i
var f=this.options.wrap !='circular'&&this.first<=1 ? 1 : this.first
var c=back ? this.get(f): this.get(this.last)
var j=back ? f : f-1
var e=null,l=0,p=false,d=0,g
while(back ?--j>=i :++j<i){
e=this.get(j)
p=!e.length
if(e.length==0){
e=this.create(j).addClass(this.className('jcarousel-item-placeholder'))
c[back ? 'before' : 'after' ](e)
if(this.first !=null&&this.options.wrap=='circular'&&this.options.size !==null&&(j<=0 || j>this.options.size)){
g=this.get(this.index(j))
if(g.length)
this.add(j,g.children().clone(true))}}
c=e
d=this.dimension(e)
if(p)
l+=d
if(this.first !=null&&(this.options.wrap=='circular' ||(j>=1&&(this.options.size==null || j<=this.options.size))))
pos=back ? pos+d : pos-d}
var clipping=this.clipping()
var cache=[]
var visible=0,j=i,v=0
var c=this.get(i-1)
while(++visible){
e=this.get(j)
p=!e.length
if(e.length==0){
e=this.create(j).addClass(this.className('jcarousel-item-placeholder'))
c.length==0 ? this.list.prepend(e): c[back ? 'before' : 'after' ](e)
if(this.first !=null&&this.options.wrap=='circular'&&this.options.size !==null&&(j<=0 || j>this.options.size)){
g=this.get(this.index(j))
if(g.length)
this.add(j,g.find('>*').clone(true))}}
c=e
var d=this.dimension(e)
if(d==0){
alert('jCarousel: No width/height set for items. This will cause an infinite loop. Aborting...')
return 0}
if(this.options.wrap !='circular'&&this.options.size !==null&&j>this.options.size)
cache.push(e)
else if(p)
l+=d
v+=d
if(v>=clipping)
break
j++}
for(var x=0;x<cache.length;x++)
cache[x].remove()
if(l>0){
this.list.css(this.wh,this.dimension(this.list)+l+'px')
if(back){
pos-=l
this.list.css(this.lt,$jc.intval(this.list.css(this.lt))-l+'px')}}
var last=i+visible-1
if(this.options.wrap !='circular'&&this.options.size&&last>this.options.size)
last=this.options.size
if(j>last){
visible=0,j=last,v=0
while(++visible){
var e=this.get(j--)
if(!e.length)
break
v+=this.dimension(e)
if(v>=clipping)
break}}
var first=last-visible+1
if(this.options.wrap !='circular'&&first<1)
first=1
if(this.inTail&&back){
pos+=this.tail
this.inTail=false}
this.tail=null
if(this.options.wrap !='circular'&&last==this.options.size&&(last-visible+1)>=1){
var m=$jc.margin(this.get(last),!this.options.vertical ? 'marginRight' : 'marginBottom')
if((v-m)>clipping)
this.tail=v-clipping-m}
while(i-->first)
pos+=this.dimension(this.get(i))
this.prevFirst=this.first
this.prevLast=this.last
this.first=first
this.last=last
return pos
},
animate: function(p,a){
if(this.locked || this.animating)
return
this.animating=true
var self=this
var scrolled=function(){
self.animating=false
if(p==0)
self.list.css(self.lt,0)
if(self.options.wrap=='circular' || self.options.wrap=='both' || self.options.wrap=='last' || self.options.size==null || self.last<self.options.size)
self.startAuto()
self.buttons()
self.notify('onAfterAnimation')}
this.notify('onBeforeAnimation')
if(!this.options.animation || a==false){
this.list.css(this.lt,p+'px')
scrolled()
}else{
var o=!this.options.vertical ?{'left': p}:{'top': p}
this.list.animate(o,this.options.animation,this.options.easing,scrolled)}
},
startAuto: function(s){
if(s !=undefined)
this.options.auto=s
if(this.options.auto==0)
return this.stopAuto()
if(this.timer !=null)
return
var self=this
this.timer=setTimeout(function(){self.next();},this.options.auto*1000)
},
stopAuto: function(){
if(this.timer==null)
return
clearTimeout(this.timer)
this.timer=null
},
buttons: function(n,p){
if(n==undefined || n==null){
var n=!this.locked&&this.options.size !==0&&((this.options.wrap&&this.options.wrap !='first')|| this.options.size==null || this.last<this.options.size)
if(!this.locked&&(!this.options.wrap || this.options.wrap=='first')&&this.options.size !=null&&this.last>=this.options.size)
n=this.tail !=null&&!this.inTail}
if(p==undefined || p==null){
var p=!this.locked&&this.options.size !==0&&((this.options.wrap&&this.options.wrap !='last')|| this.first>1)
if(!this.locked&&(!this.options.wrap || this.options.wrap=='last')&&this.options.size !=null&&this.first==1)
p=this.tail !=null&&this.inTail}
var self=this
this.buttonNext[n ? 'bind' : 'unbind'](this.options.buttonNextEvent+'.jcarousel',this.funcNext)[n ? 'removeClass' : 'addClass'](this.className('jcarousel-next-disabled')).attr('disabled',n ? false : true)
this.buttonPrev[p ? 'bind' : 'unbind'](this.options.buttonPrevEvent+'.jcarousel',this.funcPrev)[p ? 'removeClass' : 'addClass'](this.className('jcarousel-prev-disabled')).attr('disabled',p ? false : true)
if(this.buttonNext.length>0&&(this.buttonNext[0].jcarouselstate==undefined || this.buttonNext[0].jcarouselstate !=n)&&this.options.buttonNextCallback !=null){
this.buttonNext.each(function(){self.options.buttonNextCallback(self,this,n);})
this.buttonNext[0].jcarouselstate=n}
if(this.buttonPrev.length>0&&(this.buttonPrev[0].jcarouselstate==undefined || this.buttonPrev[0].jcarouselstate !=p)&&this.options.buttonPrevCallback !=null){
this.buttonPrev.each(function(){self.options.buttonPrevCallback(self,this,p);})
this.buttonPrev[0].jcarouselstate=p}
},
notify: function(evt){
var state=this.prevFirst==null ? 'init' :(this.prevFirst<this.first ? 'next' : 'prev')
this.callback('itemLoadCallback',evt,state)
if(this.prevFirst !==this.first){
this.callback('itemFirstInCallback',evt,state,this.first)
this.callback('itemFirstOutCallback',evt,state,this.prevFirst)}
if(this.prevLast !==this.last){
this.callback('itemLastInCallback',evt,state,this.last)
this.callback('itemLastOutCallback',evt,state,this.prevLast)}
this.callback('itemVisibleInCallback',evt,state,this.first,this.last,this.prevFirst,this.prevLast)
this.callback('itemVisibleOutCallback',evt,state,this.prevFirst,this.prevLast,this.first,this.last)
},
callback: function(cb,evt,state,i1,i2,i3,i4){
if(this.options[cb]==undefined ||(typeof this.options[cb] !='object'&&evt !='onAfterAnimation'))
return
var callback=typeof this.options[cb]=='object' ? this.options[cb][evt] : this.options[cb]
if(!$.isFunction(callback))
return
var self=this
if(i1===undefined)
callback(self,state,evt)
else if(i2===undefined)
this.get(i1).each(function(){callback(self,this,i1,state,evt);})
else{
for(var i=i1;i<=i2;i++)
if(i !==null&&!(i>=i3&&i<=i4))
this.get(i).each(function(){callback(self,this,i,state,evt);})}
},
create: function(i){
return this.format('<li></li>',i)
},
format: function(e,i){
var $e=$(e).addClass(this.className('jcarousel-item')).addClass(this.className('jcarousel-item-'+i)).css({
'float': 'left',
'list-style': 'none'
})
$e.attr('jcarouselindex',i)
return $e
},
className: function(c){
return c+' '+c+(!this.options.vertical ? '-horizontal' : '-vertical')
},
dimension: function(e,d){
var el=e.jquery !=undefined ? e[0] : e
var old=!this.options.vertical ?
el.offsetWidth+$jc.margin(el,'marginLeft')+$jc.margin(el,'marginRight'):
el.offsetHeight+$jc.margin(el,'marginTop')+$jc.margin(el,'marginBottom')
if(d==undefined || old==d)
return old
var w=!this.options.vertical ?
d-$jc.margin(el,'marginLeft')-$jc.margin(el,'marginRight'):
d-$jc.margin(el,'marginTop')-$jc.margin(el,'marginBottom')
$(el).css(this.wh,w+'px')
return this.dimension(el)
},
clipping: function(){
return !this.options.vertical ?
this.clip[0].offsetWidth-$jc.intval(this.clip.css('borderLeftWidth'))-$jc.intval(this.clip.css('borderRightWidth')):
this.clip[0].offsetHeight-$jc.intval(this.clip.css('borderTopWidth'))-$jc.intval(this.clip.css('borderBottomWidth'))
},
index: function(i,s){
if(s==undefined)
s=this.options.size
return Math.round((((i-1)/s)-Math.floor((i-1)/s))*s)+1}
})
$jc.extend({
defaults: function(d){
return $.extend(defaults,d ||{})
},
margin: function(e,p){
if(!e)
return 0
var el=e.jquery !=undefined ? e[0] : e
if(p=='marginRight'&&$.browser.safari){
var old={'display': 'block','float': 'none','width': 'auto'},oWidth,oWidth2
$.swap(el,old,function(){oWidth=el.offsetWidth;})
old['marginRight']=0
$.swap(el,old,function(){oWidth2=el.offsetWidth;})
return oWidth2-oWidth}
return $jc.intval($.css(el,p))
},
intval: function(v){
v=parseInt(v)
return isNaN(v)? 0 : v}
})
})(jQuery)
