1/**� * Tabs - jQuery plugin for accessible, unobtrusive tabs� * @requires jQuery v1.0.3� *� * http://stilbuero.de/tabs/� *� * Copyright (c) 2006 Klaus Hartl (stilbuero.de)� * Dual licensed under the MIT and GPL licenses:� * http://www.opensource.org/licenses/mit-license.php� * http://www.gnu.org/licenses/gpl.html� *� * Version: 2.7.3� */�(function($) { // block scope�$.extend({� tabs: {� remoteCount: 0 // TODO in Tabs 3 this is going to be more cleanly in one single namespace� }�});�/**� * Create an accessible, unobtrusive tab interface based on a particular HTML structure.� *� * The underlying HTML has to look like this:� *� * <div id="container">� * <ul>� * <li><a href="#fragment-1">Section 1</a></li>� * <li><a href="#fragment-2">Section 2</a></li>� * <li><a href="#fragment-3">Section 3</a></li>� * </ul>� * <div id="fragment-1">� *� * </div>� * <div id="fragment-2">� *� * </div>� * <div id="fragment-3">� *� * </div>� * </div>� *� * Each anchor in the unordered list points directly to a section below represented by one of the� * divs (the URI in the anchor's href attribute refers to the fragment with the corresponding id).� * Because such HTML structure is fully functional on its own, e.g. without JavaScript, the tab� * interface is accessible and unobtrusive.� *� * A tab is also bookmarkable via hash in the URL. Use the History/Remote plugin (Tabs will� * auto-detect its presence) to fix the back (and forward) button.� *� * @example $('#container').tabs();� * @desc Create a basic tab interface.� * @example $('#container').tabs(2);� * @desc Create a basic tab interface with the second tab initially activated.� * @example $('#container').tabs({disabled: [3, 4]});� * @desc Create a tab interface with the third and fourth tab being disabled.� * @example $('#container').tabs({fxSlide: true});� * @desc Create a tab interface that uses slide down/up animations for showing/hiding tab� * content upon tab switching.� *� * @param Number initial An integer specifying the position of the tab (no zero-based index) that� * gets activated at first (on page load). Two alternative ways to specify� * the active tab will overrule this argument. First a li element� * (representing one single tab) belonging to the selected tab class, e.g.� * set the selected tab class (default: "tabs-selected", see option� * selectedClass) for one of the unordered li elements in the HTML source.� * In addition if a fragment identifier/hash in the URL of the page refers� * to the id of a tab container of a tab interface the corresponding tab will� * be activated and both the initial argument as well as an eventually� * declared class attribute will be overruled. Defaults to 1 if omitted.� * @param Object settings An object literal containing key/value pairs to provide optional settings.� * @option Array<Number> disabled An array containing the position of the tabs (no zero-based index)� * that should be disabled on initialization. Default value: null.� * A tab c
1an also be disabled by simply adding the disabling class� * (default: "tabs-disabled", see option disabledClass) to the li� * element representing that particular tab.� * @option Boolean bookmarkable Boolean flag indicating if support for bookmarking and history (via� * changing hash in the URL of the browser) is enabled. Default value:� * false, unless the History/Remote plugin is included. In that case the� * default value becomes true. @see $.ajaxHistory.initialize� * @option Boolean remote Boolean flag indicating that tab content has to be loaded remotely from� * the url given in the href attribute of the tab menu anchor elements.� * @option String spinner The content of this string is shown in a tab while remote content is loading.� * Insert plain text as well as an img here. To turn off this notification� * pass an empty string or null. Default: "Loading…".� * @option String hashPrefix A String that is used for constructing the hash the link's href attribute� * of a remote tab gets altered to, such as "#remote-1".� * Default value: "remote-tab-".� * @option Boolean fxFade Boolean flag indicating whether fade in/out animations are used for tab� * switching. Can be combined with fxSlide. Will overrule fxShow/fxHide.� * Default value: false.� * @option Boolean fxSlide Boolean flag indicating whether slide down/up animations are used for tab� * switching. Can be combined with fxFade. Will overrule fxShow/fxHide.� * Default value: false.� * @option String|Number fxSpeed A string representing one of the three predefined speeds ("slow",� * "normal", or "fast") or the number of milliseconds (e.g. 1000) to� * run an animation. Default value: "normal".� * @option Object fxShow An object literal of the form jQuery's animate function expects for making� * your own, custom animation to reveal a tab upon tab switch. Unlike fxFade� * or fxSlide this animation is independent from an optional hide animation.� * Default value: null. @see animate� * @option Object fxHide An object literal of the form jQuery's animate function expects for making� * your own, custom animation to hide a tab upon tab switch. Unlike fxFade� * or fxSlide this animation is independent from an optional show animation.� * Default value: null. @see animate� * @option String|Number fxShowSpeed A string representing one of the three predefined speeds� * ("slow", "normal", or "fast") or the number of milliseconds� * (e.g. 1000) to run the animation specified in fxShow.� * Default value: fxSpeed.� * @option String|Number fxHideSpeed A string representing one of the three predefined speeds� * ("slow", "normal", or "fast") or the number of milliseconds� * (e.g. 1000) to run the animation specified in fxHide.� * Default value: fxSpeed.� * @option Boolean fxAutoHeight Boolean flag that if set to true causes all tab heights� * to be constant (being the height of the tallest tab).� * Default value: false.� * @option Function onClick A function to be invoked upon tab switch, immediatly after a tab has� * been clicked, e.g. before the other's tab content gets hidden. The� * function gets passed three arguments: the first one is the clicked� * tab (e.g. an anchor element), the second one is the DOM element� * containing the content of the clicked tab (e.g. the div), the third� * argument is the one of the tab that gets hidden. If this callback� * returns false, the tab switch is canceled (use to disallow tab� * switching for the reason of a failed form validation for example).� * Default value: null.� * @option Function onHide A function to be invoked upon tab switch, immediatly after one tab's� * content got hidden (with or without an animation) and right before the� * next tab is revealed. The function gets passed three arguments: the� * first one is the clicked tab (e.g. an anchor element), the second one� * is the DOM element containing the content of the clicked tab, (e.g. the� * div), the third argument is the one of the tab that gets hidden.� * Default value: null.� * @option Function onShow A function to be invoked upon tab switch. This function is invoked� * after the new tab has been revealed, e.g. after the switch is completed.� * The function gets passed three arguments: the first one is the clicked� * tab (e.g. an anchor element), the second one is the DOM element� * containing the content of the clicked tab, (e.g. the div), the third� * argument is the one of the tab that gets hidden. Default value: null.� * @option String navClass A CSS class that is used to identify the tabs unordered list by class if� * the required HTML structure differs from the default one.� * Default value: "tabs-nav".� * @option String selectedClass The CSS class attached to the li element representing the� * currently selected (active) tab. Default value: "tabs-selected".� * @option String disabledClass The CSS class attached to the li element representing a disabled� * tab. Default value: "tabs-disabled".� * @option String containerClass A CSS class that is used to identify tab containers by class if� * the required HTML structure differs from the default one.� * Default value: "tabs-container".� * @option String hideClass The CSS class used for hiding inactive tabs. A class is used instead� * of "display: none" in the style attribute to maintain control over� * visibility in other media types than screen, most notably print.� * Default value: "tabs-hide".� * @option String loadingClass The CSS class used for indicating that an Ajax tab is currently� * loading, for example by showing a spinner.� * Default value: "tabs-loading".� * @option String tabStruct @deprecated A CSS selector or basic XPath expression reflecting a� * nested HTML structure that is different from the default single div� * structure (one div with an id inside the overall container holds one� * tab's content). If for instance an additional div is required to wrap� * up the several tab containers such a structure is expressed by "div>div".� * Default value: "div".� * @type jQuery� *� * @name tabs� * @cat Plugins/Tabs� * @author Klaus Hartl/[email protected]� */�$.fn.tabs = function(initial, settings) {� // settings� if (typeof initial == 'object') settings = initial; // no initial tab given but a settings object� settings = $.extend({� initial: (initial && typeof initial == 'number' && initial > 0) ? --initial : 0,� disabled: null,� bookmarkable: $.ajaxHistory ? true : false,� remote: false,� spinner: 'Loa
1ding…',� hashPrefix: 'remote-tab-',� fxFade: null,� fxSlide: null,� fxShow: null,� fxHide: null,� fxSpeed: 'normal',� fxShowSpeed: null,� fxHideSpeed: null,� fxAutoHeight: false,� onClick: null,� onHide: null,� onShow: null,� navClass: 'tabs-nav',� selectedClass: 'tabs-selected',� disabledClass: 'tabs-disabled',� containerClass: 'tabs-container',� hideClass: 'tabs-hide',� loadingClass: 'tabs-loading',� tabStruct: 'div'� }, settings || {});� $.browser.msie6 = $.browser.msie6 || $.browser.msie && typeof XMLHttpRequest == 'function';� // helper to prevent scroll to fragment� function unFocus() {� scrollTo(0, 0);� }� // initialize tabs� return this.each(function() {� // remember wrapper for later� var container = this;� // setup nav� var nav = $('ul.' + settings.navClass, container);� nav = nav.size() && nav || $('>ul:eq(0)', container); // fallback to default structure� var tabs = $('a', nav);� // prepare remote tabs� if (settings.remote) {� tabs.each(function() {� var id = settings.hashPrefix + (++$.tabs.remoteCount), hash = '#' + id, url = this.href;� this.href = hash;� $('<div id="' + id + '" class="' + settings.containerClass + '"></div>').appendTo(container);� $(this).bind('loadRemoteTab', function(e, callback) {� var $$ = $(this).addClass(settings.loadingClass), span = $('span', this)[0], tabTitle = span.innerHTML;� if (settings.spinner) {� // TODO if spinner is image� span.innerHTML = '<em>' + settings.spinner + '</em>'; // WARNING: html(...) crashes Safari with jQuery 1.1.2� }� setTimeout(function() { // Timeout is again required in IE, "wait" for id being restored� $(hash).load(url, function() {� if (settings.spinner) {� span.innerHTML = tabTitle; // WARNING: html(...) crashes Safari with jQuery 1.1.2� }� $$.removeClass(settings.loadingClass);� callback && callback();� });� }, 0);� });� });� }� // set up containers� var containers = $('div.' + settings.containerClass, container);� containers = containers.size() && containers || $('>' + settings.tabStruct, container); // fallback to default structure� // attach classes for styling if not present� nav.is('.' + settings.navClass) || nav.addClass(settings.navClass);� containers.each(function() {� var $$ = $(this);� $$.is('.' + settings.containerClass) || $$.addClass(settings.containerClass);� });� // try to retrieve active tab from class in HTML� var hasSelectedClass = $('li', nav).index( $('li.' + settings.selectedClass, nav)[0] );� if (hasSelectedClass >= 0) {� settings.initial = hasSelectedClass;� }� // try to retrieve active tab from hash in url, will override class in HTML� if (location.hash) {� tabs.each(function(i) {� if (this.hash == location.hash) {� settings.initial = i;� // prevent page scroll to fragment� if (($.browser.msie || $.browser.opera) && !settings.remote) {� var toShow = $(location.hash);� var toShowId = toShow.attr('id');� toShow.attr('id', '');� setTimeout(function() {� toShow.attr('id', toShowId); // restore id� }, 500);� }� unFocus();� return false; // break� }� });� }� if ($.browser.msie) {� unFocus(); // fix IE focussing bottom of the page for some unknown reason� }� // highlight tab accordingly� containers.filter(':eq(' + settings.initial + ')').show().end().not(':eq(' + settings.initial + ')').addClass(settings.hideClass);� $('li', nav).removeClass(settings.selectedClass).eq(settings.initial).addClass(settings.selectedClass); // we need to remove classes eventually if hash takes precedence over class� // trigger load of initial tab� tabs.eq(settings.initial).trigger('loadRemoteTab').end();� // setup auto height� if (settings.fxAutoHeight) {� // helper� var _setAutoHeight = function(reset) {� // get tab heights in to
1p to bottom ordered array� var heights = $.map(containers.get(), function(el) {� var h, jq = $(el);� if (reset) {� if ($.browser.msie6) {� el.style.removeExpression('behaviour');� el.style.height = '';� el.minHeight = null;� }� h = jq.css({'min-height': ''}).height(); // use jQuery's height() to get hidden element values� } else {� h = jq.height(); // use jQuery's height() to get hidden element values� }� return h;� }).sort(function(a, b) {� return b - a;� });� if ($.browser.msie6) {� containers.each(function() {� this.minHeight = heights[0] + 'px';� this.style.setExpression('behaviour', 'this.style.height = this.minHeight ? this.minHeight : "1px"'); // using an expression to not make print styles useless� });� } else {� containers.css({'min-height': heights[0] + 'px'});� }� };� // call once for initialization� _setAutoHeight();� // trigger auto height adjustment if needed� var cachedWidth = container.offsetWidth;� var cachedHeight = container.offsetHeight;� var watchFontSize = $('#tabs-watch-font-size').get(0) || $('<span id="tabs-watch-font-size">M</span>').css({display: 'block', position: 'absolute', visibility: 'hidden'}).appendTo(document.body).get(0);� var cachedFontSize = watchFontSize.offsetHeight;� setInterval(function() {� var currentWidth = container.offsetWidth;� var currentHeight = container.offsetHeight;� var currentFontSize = watchFontSize.offsetHeight;� if (currentHeight > cachedHeight || currentWidth != cachedWidth || currentFontSize != cachedFontSize) {� _setAutoHeight((currentWidth > cachedWidth || currentFontSize < cachedFontSize)); // if heights gets smaller reset min-height� cachedWidth = currentWidth;� cachedHeight = currentHeight;� cachedFontSize = currentFontSize;� }� }, 50);� }� // setup animations� var showAnim = {}, hideAnim = {}, showSpeed = settings.fxShowSpeed || settings.fxSpeed, hideSpeed = settings.fxHideSpeed || settings.fxSpeed;� if (settings.fxSlide || settings.fxFade) {� if (settings.fxSlide) {� showAnim['height'] = 'show';� hideAnim['height'] = 'hide';� }� if (settings.fxFade) {� showAnim['opacity'] = 'show';� hideAnim['opacity'] = 'hide';� }� } else {� if (settings.fxShow) {� showAnim = settings.fxShow;� } else { // use some kind of animation to prevent browser scrolling to the tab� showAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox� showSpeed = settings.bookmarkable ? 50 : 1; // as little as 50 is sufficient� }� if (settings.fxHide) {� hideAnim = settings.fxHide;� } else { // use some kind of animation to prevent browser scrolling to the tab� hideAnim['min-width'] = 0; // avoid opacity, causes flicker in Firefox� hideSpeed = settings.bookmarkable ? 50 : 1; // as little as 50 is sufficient� }� }� // callbacks� var onClick = settings.onClick, onHide = settings.onHide, onShow = settings.onShow;� // attach activateTab event, required for activating a tab programmatically� tabs.bind('triggerTab', function() {� // if the tab is already selected or disabled or animation is still running stop here� var li = $(this).parents('li:eq(0)');� if (container.locked || li.is('.' + settings.selectedClass) || li.is('.' + settings.disabledClass)) {� return false;� }� var hash = this.hash;� if ($.browser.msie) {� $(this).trigger('click');� if (settings.bookmarkable) {� $.ajaxHistory.update(hash);� location.hash = hash.replace('#', '');� }� } else if ($.browser.safari) {� // Simply setting location.hash puts Safari into the eternal load state... ugh! Submit a form instead.� var tempForm = $('<form action="' + hash + '"><div><input type="submit" value="h" /></div></form>').get(0); // no need to append it to the body� tempForm.submit(); // does not trigger the form's submit event...� $(this).trigger('click'); // ...thus do stuff here� if (settings.bookmarkable) {� $.ajaxHistory.update(hash);� }� } else {� if (settings.bookmarkable) {� location.hash = hash.replace('#', '');� } else {� $(this).trigger('click');� }� }� });� // attach disable event, required for disabling a tab� tabs.bind('disableTab', function() {� var li = $(this).parents('li:eq(0)');� if ($.browser.safari) { /* Fix opacity of tab after disabling in Safari... */� li.animate({ opacity: 0 }, 1, function() {� li.css({opacity: ''});� });� }� li.addClass(settings.disabledClass);� });� // disabled from settings� if (settings.disabled && settings.disabled.length) {� for (var i = 0, k = settings.disabled.length; i < k; i++) {� tabs.eq(--settings.disabled[i]).trigger('disableTab').end();� }� };� // attach enable event, required for reenabling a tab� tabs.bind('enableTab', function() {� var li = $(this).parents('li:eq(0)');� li.removeClass(settings.disabledClass);� if ($.browser.safari) { /* Fix disappearing tab after enabling in Safari... */� li.animate({ opacity: 1 }, 1, function() {� li.css({opacity: ''});� });� }� });� // attach click event� tabs.bind('click', function(e) {� var trueClick = e.clientX; // add to history only if true click occured, not a triggered click� var clicked = this, li = $(this).parents('li:eq(0)'), toShow = $(this.hash), toHide = containers.filter(':visible');� // if animation is still running, tab is selected or disabled or onClick callback returns false stop here� // check if onClick returns false last so that it is not executed for a disabled tab� if (container['locked'] || li.is('.' + settings.selectedClass) || li.is('.' + settings.disabledClass) || typeof onClick == 'function' && onClick(this, toShow[0], toHide[0]) === false) {� this.blur();� return false;� }� container['locked'] = true;� // show new tab� if (toShow.size()) {� // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled� if ($.browser.msie && settings.bookmarkable) {� var toShowId = this.hash.replace('#', '');� toShow.attr('id', '');� setTimeout(function() {� toShow.attr('id', toShowId); // restore id� }, 0);� }� // switch tab, animation prevents browser scrolling to the fragment� function switchTab() {� if (settings.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click� $.ajaxHistory.update(clicked.hash);� }� toHide.animate(hideAnim, hideSpeed, function() { //� $(clicked).parents('li:eq(0)').addClass(settings.selectedClass).siblings().removeClass(settings.selectedClass);� if (typeof onHide == 'function') {� onHide(clicked, toShow[0], toHide[0]);� }
1� var resetCSS = { display: '', overflow: '', height: '' };� if (!$.browser.msie) { // not in IE to prevent ClearType font issue� resetCSS['opacity'] = '';� }� toHide.addClass(settings.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.� toShow.removeClass(settings.hideClass).animate(showAnim, showSpeed, function() {� toShow.css(resetCSS); // maintain flexible height and accessibility in print etc.� if ($.browser.msie) {� toHide[0].style.filter = '';� toShow[0].style.filter = '';� }� if (typeof onShow == 'function') {� onShow(clicked, toShow[0], toHide[0]);� }� container['locked'] = null;� });� });� }� if (!settings.remote) {� switchTab();� } else {� $(clicked).trigger('loadRemoteTab', [switchTab]);� }� } else {� alert('There is no such container.');� }� // 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() {� window.scrollTo(scrollX, scrollY);� }, 0);� this.blur(); // prevent IE from keeping other link focussed when using the back button� return settings.bookmarkable && !!trueClick; // convert undefined to Boolean for IE� });� // enable history support if bookmarking and history is turned on� if (settings.bookmarkable) {� $.ajaxHistory.initialize(function() {� tabs.eq(settings.initial).trigger('click').end();� });� }� });�};�/**� * Activate a tab programmatically with the given position (no zero-based index)� * or its id, e.g. the URL's fragment identifier/hash representing a tab, as if the tab� * itself were clicked.� *� * @example $('#container').triggerTab(2);� * @desc Activate the second tab of the tab interface contained in <div id="container">.� * @example $('#container').triggerTab(1);� * @desc Activate the first tab of the tab interface contained in <div id="container">.� * @example $('#container').triggerTab();� * @desc Activate the first tab of the tab interface contained in <div id="container">.� * @example $('#container').triggerTab('fragment-2');� * @desc Activate a tab via its URL fragment identifier representation.� *� * @param String|Number tab Either a string that matches the id of the tab (the URL's� * fragment identifier/hash representing a tab) or an integer� * specifying the position of the tab (no zero-based index) to� * be activated. If this parameter is omitted, the first tab� * will be activated.� * @type jQuery� *� * @name triggerTab� * @cat Plugins/Tabs� * @author Klaus Hartl/[email protected]� */�/**� * Disable a tab, so that clicking it has no effect.� *� * @example $('#container').disableTab(2);� * @desc Disable the second tab of the tab interface contained in <div id="container">.� *� * @param String|Number tab Either a string that matches the id of the tab (the URL's� * fragment identifier/hash representing a tab) or an integer� * specifying the position of the tab (no zero-based index) to� * be disabled. If this parameter is omitted, the first tab� * will be disabled.� * @type jQuery� *� * @name disableTab� * @cat Plugins/Tabs� * @author Klaus Hartl/[email protected]� */�/**� * Enable a tab that has been disabled.� *� * @example $('#container').enableTab(2);� * @desc Enable the second tab of the tab interface contained in <div id="container">.� *� * @param String|Number tab Either a string that matches the id of the tab (the URL's� * fragment identifier/hash representing a tab) or an integer� * specifying the position of the tab (no zero-based index) to� * be enabled. If this parameter is omitted, the first tab� * will be enabled.� * @type jQuery� *� * @name enableTab� * @cat Plugins/Tabs� * @author Klaus Hartl/[email protected]� */�var tabEvents = ['triggerTab', 'disableTab', 'enableTab'];�for (var i = 0; i < tabEvents.length; i++) {� $.fn[tabEvents[i]] = (function(tabEvent) {� return function(tab) {� return this.each(function() {� var nav = $('ul.tabs-nav' , this);� nav = nav.size() && nav || $('>ul:eq(0)', this); // fallback to default structure� var a;� if (!tab || typeof tab == 'number') {� a = $('li a', nav).eq((tab && tab > 0 && tab - 1 || 0)); // fall back to 0� } else if (typeof tab == 'string') {� a = $('li a[@href$="#' + tab + '"]', nav);� }� a.trigger(tabEvent);� });� };� })(tabEvents[i]);�}�/**� * Get the position of the currently selected tab (no zero-based index).� *� * @example $('#container').activeTab();� * @desc Get the position of the currently selected tab of an interface� * contained in <div id="container">.� *� * @type Number� *� * @name activeTab� * @cat Plugins/Tabs� * @author Klaus Hartl/[email protected]� */�$.fn.activeTab = function() {� var selectedTabs = [];� this.each(function() {� var nav = $('ul.tabs-nav' , this);� nav = nav.size() && nav || $('>ul:eq(0)', this); //fallback to default structure� var lis = $('li', nav);� selectedTabs.push(lis.index( lis.filter('.tabs-selected')[0] ) + 1);� });� return selectedTabs[0];�};�})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.