/* * jQuery UI Tabs @VERSION * * Copyright (c) 2007, 2010 Klaus Hartl (stilbuero.de) * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * * http://docs.jquery.com/UI/Tabs * * Depends: * ui.core.js */(function($){$.widget("ui.tabs",{_init:function(){this.options.event+='.tabs';// namespace event// create tabsthis._tabify(true);},_setData:function(key,value){if((/^selected/).test(key))this.select(value);else{this.options[key]=value;this._tabify();}},length:function(){returnthis.$tabs.length;},_tabId:function(a){returna.title&&a.title.replace(/\s/g,'_').replace(/[^A-Za-z0-9\-_:\.]/g,'')||this.options.idPrefix+$.data(a);},ui:function(tab,panel){return{options:this.options,tab:tab,panel:panel,index:this.$tabs.index(tab)};},_tabify:function(init){this.$lis=$('li:has(a[href])',this.element);this.$tabs=this.$lis.map(function(){return$('a',this)[0];});this.$panels=$([]);varself=this,o=this.options;this.$tabs.each(function(i,a){// inline tabif(a.hash&&a.hash.replace('#',''))// Safari 2 reports '#' for an empty hashself.$panels=self.$panels.add(a.hash);// remote tabelseif($(a).attr('href')!='#'){// prevent loading the page itself if href is just "#"$.data(a,'href.tabs',a.href);// required for restore on destroy$.data(a,'load.tabs',a.href);// mutablevarid=self._tabId(a);a.href='#'+id;var$panel=$('#'+id);if(!$panel.length){$panel=$(o.panelTemplate).attr('id',id).addClass(o.panelClass).insertAfter(self.$panels[i-1]||self.element);$panel.data('destroy.tabs',true);}self.$panels=self.$panels.add($panel);}// invalid tab hrefelseo.disabled.push(i+1);});// initialization from scratchif(init){// attach necessary classes for styling if not presentthis.element.addClass(o.navClass);this.$panels.each(function(){var$this=$(this);$this.addClass(o.panelClass);});// Selected tab// use "selected" option or try to retrieve:// 1. from fragment identifier in url// 2. from cookie// 3. from selected class attribute on <li>if(o.selected===undefined){if(location.hash){this.$tabs.each(function(i,a){if(a.hash==location.hash){o.selected=i;// prevent page scroll to fragmentif($.browser.msie||$.browser.opera){// && !o.remotevar$toShow=$(location.hash),toShowId=$toShow.attr('id');$toShow.attr('id','');setTimeout(function(){$toShow.attr('id',toShowId);// restore id},500);}scrollTo(0,0);returnfalse;// break}});}elseif(o.cookie){varindex=parseInt($.cookie('ui-tabs-'+$.data(self.element[0])),10);if(index&&self.$tabs[index])o.selected=index;}elseif(self.$lis.filter('.'+o.selectedClass).length)o.selected=self.$lis.index(self.$lis.filter('.'+o.selectedClass)[0]);}o.selected=o.selected===null||o.selected!==undefined?o.selected:0;// first tab selected by default// Take disabling tabs via class attribute from HTML// into account and update option properly.// A selected tab cannot become disabled.o.disabled=$.unique(o.disabled.concat($.map(this.$lis.filter('.'+o.disabledClass),function(n,i){returnself.$lis.index(n);}))).sort();if($.inArray(o.selected,o.disabled)!=-1)o.disabled.splice($.inArray(o.selected,o.disabled),1);// highlight selected tabthis.$panels.addClass(o.hideClass);this.$lis.removeClass(o.selectedClass);if(o.selected!==null){this.$panels.eq(o.selected).show().removeClass(o.hideClass);// use show and remove class to show in any case no matter how it has been hidden beforethis.$lis.eq(o.selected).addClass(o.selectedClass);// seems to be expected behavior that the show callback is firedvaronShow=function(){self._trigger('show',null,self.ui(self.$tabs[o.selected],self.$panels[o.selected]));};// load if remote tabif($.data(this.$tabs[o.selected],'load.tabs'))this.load(o.selected,onShow);// just trigger show eventelseonShow();}// clean up to avoid memory leaks in certain versions of IE 6$(window).bind('unload',function(){self.$tabs.unbind('.tabs');self.$lis=self.$tabs=self.$panels=null;});}// update selected after add/removeelseo.selected=this.$lis.index(this.$lis.filter('.'+o.selectedClass)[0]);// set or update cookie after init and add/remove respectivelyif(o.cookie)$.cookie('ui-tabs-'+$.data(self.element[0]),o.selected,o.cookie);// disable tabsfor(vari=0,li;li=this.$lis[i];i++)$(li)[$.inArray(i,o.disabled)!=-1&&!$(li).hasClass(o.selectedClass)?'addClass':'removeClass'](o.disabledClass);// reset cache if switching from cached to not cachedif(o.cache===false)this.$tabs.removeData('cache.tabs');// set up animationsvarhideFx,showFx,baseFx={'min-width':0,duration:1},baseDuration='normal';if(o.fx&&o.fx.constructor==Array)hideFx=o.fx[0]||baseFx,showFx=o.fx[1]||baseFx;elsehideFx=showFx=o.fx||baseFx;// reset some styles to maintain print style sheets etc.varresetCSS={display:'',overflow:'',height:''};if(!$.browser.msie)// not in IE to prevent ClearType font issueresetCSS.opacity='';// Hide a tab, animation prevents browser scrolling to fragment,// $show is optional.functionhideTab(clicked,$hide,$show){$hide.animate(hideFx,hideFx.duration||baseDuration,function(){//$hide.addClass(o.hideClass).css(resetCSS);// maintain flexible height and accessibility in print etc.if($.browser.msie&&hideFx.opacity)$hide[0].style.filter='';if($show)showTab(clicked,$show,$hide);});}// Show a tab, animation prevents browser scrolling to fragment,// $hide is optional.functionshowTab(clicked,$show,$hide){if(showFx===baseFx)$show.css('display','block');// prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels$show.animate(showFx,showFx.duration||baseDuration,function(){$show.removeClass(o.hideClass).css(resetCSS);// maintain flexible height and accessibility in print etc.if($.browser.msie&&showFx.opacity)$show[0].style.filter='';// callbackself._trigger('show',null,self.ui(clicked,$show[0]));});}// switch a tabfunctionswitchTab(clicked,$li,$hide,$show){/*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click $.ajaxHistory.update(clicked.hash); }*/$li.addClass(o.selectedClass).siblings().removeClass(o.selectedClass);hideTab(clicked,$hide,$show);}// attach tab event handler, unbind to avoid duplicates from former tabifying...this.$tabs.unbind('.tabs').bind(o.event,function(){//var trueClick = e.clientX; // add to history only if true click occured, not a triggered clickvar$li=$(this).parents('li:eq(0)'),$hide=self.$panels.filter(':visible'),$show=$(this.hash);// If tab is already selected and not unselectable or tab disabled or // or is already loading or click callback returns false stop here.// Check if click handler returns false last so that it is not executed// for a disabled or loading tab!if(($li.hasClass(o.selectedClass)&&!o.unselect)||$li.hasClass(o.disabledClass)||$(this).hasClass(o.loadingClass)||self._trigger('select',null,self.ui(this,$show[0]))===false){this.blur();returnfalse;}self.options.selected=self.$tabs.index(this);// if tab may be closedif(o.unselect){if($li.hasClass(o.selectedClass)){self.options.selected=null;$li.removeClass(o.selectedClass);self.$panels.stop();hideTab(this,$hide);this.blur();returnfalse;}elseif(!$hide.length){self.$panels.stop();vara=this;self.load(self.$tabs.index(this),function(){$li.addClass(o.selectedClass).addClass(o.unselectClass);showTab(a,$show);});this.blur();returnfalse;}}if(o.cookie)$.cookie('ui-tabs-'+$.data(self.element[0]),self.options.selected,o.cookie);// stop possibly running animationsself.$panels.stop();// show new tabif($show.length){// prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled/*if ($.browser.msie && o.bookmarkable) { var showId = this.hash.replace('#', ''); $show.attr('id', ''); setTimeout(function() { $show.attr('id', showId); // restore id }, 0); }*/vara=this;self.load(self.$tabs.index(this),$hide.length?function(){switchTab(a,$li,$hide,$show);}:function(){$li.addClass(o.selectedClass);showTab(a,$show);});// Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash/*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0; var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0; setTimeout(function() { scrollTo(scrollX, scrollY); }, 0);*/}elsethrow'jQuery UI Tabs: Mismatching fragment identifier.';// Prevent IE from keeping other link focussed when using the back button// and remove dotted border from clicked link. This is controlled in modern// browsers via CSS, also blur removes focus from address bar in Firefox// which can become a usability and annoying problem with tabsRotate.if($.browser.msie)this.blur();//return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IEreturnfalse;});// disable click if event is configured to something elseif(!(/^click/).test(o.event))this.$tabs.bind('click.tabs',function(){returnfalse;});},add:function(url,label,index){if(index==undefined)index=this.$tabs.length;// append by defaultvaro=this.options;var$li=$(o.tabTemplate.replace(/#\{href\}/g,url).replace(/#\{label\}/g,label));$li.data('destroy.tabs',true);varid=url.indexOf('#')==0?url.replace('#',''):this._tabId($('a:first-child',$li)[0]);// try to find an existing element before creating a new onevar$panel=$('#'+id);if(!$panel.length){$panel=$(o.panelTemplate).attr('id',id).addClass(o.hideClass).data('destroy.tabs',true);}$panel.addClass(o.panelClass);if(index>=this.$lis.length){$li.appendTo(this.element);$panel.appendTo(this.element[0].parentNode);}else{$li.insertBefore(this.$lis[index]);$panel.insertBefore(this.$panels[index]);}o.disabled=$.map(o.disabled,function(n,i){returnn>=index?++n:n});this._tabify();if(this.$tabs.length==1){$li.addClass(o.selectedClass);$panel.removeClass(o.hideClass);varhref=$.data(this.$tabs[0],'load.tabs');if(href)this.load(index,href);}// callbackthis._trigger('add',null,this.ui(this.$tabs[index],this.$panels[index]));},remove:function(index){varo=this.options,$li=this.$lis.eq(index).remove(),$panel=this.$panels.eq(index).remove();// If selected tab was removed focus tab to the right or// in case the last tab was removed the tab to the left.if($li.hasClass(o.selectedClass)&&this.$tabs.length>1)this.select(index+(index+1<this.$tabs.length?1:-1));o.disabled=$.map($.grep(o.disabled,function(n,i){returnn!=index;}),function(n,i){returnn>=index?--n:n});this._tabify();// callbackthis._trigger('remove',null,this.ui($li.find('a')[0],$panel[0]));},enable:function(index){varo=this.options;if($.inArray(index,o.disabled)==-1)return;var$li=this.$lis.eq(index).removeClass(o.disabledClass);if($.browser.safari){// fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...$li.css('display','inline-block');setTimeout(function(){$li.css('display','block');},0);}o.disabled=$.grep(o.disabled,function(n,i){returnn!=index;});// callbackthis._trigger('enable',null,this.ui(this.$tabs[index],this.$panels[index]));},disable:function(index){varself=this,o=this.options;if(index!=o.selected){// cannot disable already selected tabthis.$lis.eq(index).addClass(o.disabledClass);o.disabled.push(index);o.disabled.sort();// callbackthis._trigger('disable',null,this.ui(this.$tabs[index],this.$panels[index]));}},select:function(index){if(typeofindex=='string')index=this.$tabs.index(this.$tabs.filter('[href$='+index+']')[0]);this.$tabs.eq(index).trigger(this.options.event);},load:function(index,callback){// callback is for internal usage onlyvarself=this,o=this.options,$a=this.$tabs.eq(index),a=$a[0],bypassCache=callback==undefined||callback===false,url=$a.data('load.tabs');callback=callback||function(){};// no remote or from cache - just finish with callbackif(!url||!bypassCache&&$.data(a,'cache.tabs')){callback();return;}// load remote from here onvarinner=function(parent){var$parent=$(parent),$inner=$parent.find('*:last');return$inner.length&&$inner.is(':not(img)')&&$inner||$parent;};varcleanup=function(){self.$tabs.filter('.'+o.loadingClass).removeClass(o.loadingClass).each(function(){if(o.spinner)inner(this).parent().html(inner(this).data('label.tabs'));});self.xhr=null;};if(o.spinner){varlabel=inner(a).html();inner(a).wrapInner('<em></em>').find('em').data('label.tabs',label).html(o.spinner);}varajaxOptions=$.extend({},o.ajaxOptions,{url:url,success:function(r,s){$(a.hash).html(r);cleanup();if(o.cache)$.data(a,'cache.tabs',true);// if loaded once do not load them again// callbacksself._trigger('load',null,self.ui(self.$tabs[index],self.$panels[index]));o.ajaxOptions.success&&o.ajaxOptions.success(r,s);// This callback is required because the switch has to take// place after loading has completed. Call last in order to // fire load before show callback...callback();}});if(this.xhr){// terminate pending requests from other tabs and restore tab labelthis.xhr.abort();cleanup();}$a.addClass(o.loadingClass);setTimeout(function(){// timeout is again required in IE, "wait" for id being restoredself.xhr=$.ajax(ajaxOptions);},0);},url:function(index,url){this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs',url);},destroy:function(){varo=this.options;this.element.unbind('.tabs').removeClass(o.navClass).removeData('tabs');this.$tabs.each(function(){varhref=$.data(this,'href.tabs');if(href)this.href=href;var$this=$(this).unbind('.tabs');$.each(['href','load','cache'],function(i,prefix){$this.removeData(prefix+'.tabs');});});this.$lis.add(this.$panels).each(function(){if($.data(this,'destroy.tabs'))$(this).remove();else$(this).removeClass([o.selectedClass,o.unselectClass,o.disabledClass,o.panelClass,o.hideClass].join(' '));});}});$.ui.tabs.defaults={// basic setupunselect:false,event:'click',disabled:[],cookie:null,// e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }// TODO history: false,// Ajaxspinner:'Loading…',cache:false,idPrefix:'ui-tabs-',ajaxOptions:{},// animationsfx:null,// e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }// templatestabTemplate:'<li><a href="#{href}"><span>#{label}</span></a></li>',panelTemplate:'<div></div>',// CSS classesnavClass:'ui-tabs-nav',selectedClass:'ui-tabs-selected',unselectClass:'ui-tabs-unselect',disabledClass:'ui-tabs-disabled',panelClass:'ui-tabs-panel',hideClass:'ui-tabs-hide',loadingClass:'ui-tabs-loading'};$.ui.tabs.getter="length";/* * Tabs Extensions *//* * Rotate */$.extend($.ui.tabs.prototype,{rotation:null,rotate:function(ms,continuing){continuing=continuing||false;varself=this,t=this.options.selected;functionstart(){self.rotation=setInterval(function(){t=++t<self.$tabs.length?t:0;self.select(t);},ms);}functionstop(e){if(!e||e.clientX){// only in case of a true clickclearInterval(self.rotation);}}// start intervalif(ms){start();if(!continuing)this.$tabs.bind(this.options.event,stop);elsethis.$tabs.bind(this.options.event,function(){stop();t=self.options.selected;start();});}// stop intervalelse{stop();this.$tabs.unbind(this.options.event,stop);}}});})(jQuery);