/**
* Widget that allows developers to create a tab based navigation menu.
* The Tabs class supports both normal tabs (fields hidden based on their IDs) as well
* as tabs loaded using Ajax.
*
* In order to use the Tab class you only need some very basic markup. You'll need a
* list element (either ordered or unordered) that will contain all links and a few divs
* in case you're using regular tabs that don't load their content using Ajax. The most
* basic example looks like the following:
*
*
*
This is the content of tab #1 loaded using Ajax.
*
*
* ## Creating and Configuration
*
* Now that we know how the markup works, let's create some tabs. Doing this is fairly easy and
* at a basic level only requires the following code:
*
* Zen.Objects.MyTabs = new Zen.Tabs('css_selector_for_element');
*
* In this case we're creating a new instance of the Tabs class for an element named "css_selector_for_element".
* The first argument is a simple CSS selector that defines what element to choose. This means that you can either
* use a class or ID name but also a more complicated selector like "div > ul ul:first-child".
*
* Let's create another Tab instance but use some custom configuration options this time.
*
* Zen.Objects.MyTabs = new Zen.Tabs('ul.some_class_name',
* {
* default: 'li:last-child',
* ajax: false
* });
*
* As you can see there are configuration items available.
*
* * default: The default tab/tab field to show. Again this is just a CSS selector so you
* can easily customize it.
* * ajax: Boolean that indicates that the tabs should be loaded from an external page using
* Ajax.
*
* Special thanks to the guys from #mootools for helping me out :)
*
* @author Yorick Peterse
* @link http://yorickpeterse.com/ Yorick Peterse's Website
* @link http://zen-cms.com/ Zen Website
* @license http://code.yorickpeterse.com/license.txt The MIT license
* @since 0.1
*/
Zen.Tabs = new Class(
{
Implements: Options,
/**
* Object containing all options for each tab instance.
*
* @author Yorick Peterse
* @since 0.1
* @var {object}
*/
options:
{
// The default tab/field to display
'default': 'li:first-child',
// Specifies if the content of each tab should be loaded using Ajax.
ajax: false
},
/**
* String that contains the CSS selector that specifies which element
* should be used for creating the tabs.
*
* @author Yorick Peterse
* @since 0.1
* @var {object}
*/
element: null,
/**
* Array that will contain a list of objects for each tab/field for the
* current element. This array will be used when binding events to each
* tab so that we don't have to search for these tabs/fields over and over again.
*
* @author Yorick Peterse
* @since 0.1
* @var {array}
*/
fields: [],
/**
* Constructor method called upon initialization. Options can be
* set as a JSON object in the first argument.
*
* @author Yorick Peterse
* @since 0.1
* @param {string} element The element to use for creating the tabs.
* @param {object} options Custom options used when creating the tabs
* @return {void}
*/
initialize: function(element, options)
{
this.setOptions(options);
// Ignore the tab system if the element couldn't be found
if ( $$(element).length <= 0 )
{
return;
}
this.element = $$(element)[0];
// We're good to go
if ( this.options.ajax === false )
{
this.generalTabs();
}
else
{
this.ajaxTabs();
}
},
/**
* Generate a set of normal tabs that will load content that's already on the page.
* In order for these tabs to work your URLs will need to point to an element with
* an ID. These elements will be hidden and shown upon clicking the corresponding tab.
*
* @author Yorick Peterse
* @since 0.1
* @return {void}
*/
generalTabs: function()
{
// Create a reference to the current instance so we can
// use data in this instance in our events and loops.
var self = this;
// Select our default tab element
var default_field = this.element.getElement(self.options['default']).getElement('a');
var links = this.element.getElements('li a');
this.element.getElement(self.options['default']).addClass('active');
links.each(function(link)
{
// Hide the corresponding element
var url = link.get('href');
var field = $(url.replace('#', ''));
// Check if the field actually exists and hide it if it's a non
// default field.
if ( field !== null && default_field !== link )
{
field.setStyle('display', 'none');
}
self.fields.push({url: url, field: field});
// Add an event that will show the corresponding field for each link
link.addEvent('click', function(event)
{
// Prevent normal behavior
event.stop();
self.element.getElement('li.active').removeClass('active');
// Now we can add the class to the current tab
this.getParent('li').addClass('active');
// Toggle the state of each tab and ignore any non-existing fields.
self.fields.each(function(item)
{
if ( item === null || item.field === null )
{
return;
}
if ( item.url === link.get('href') )
{
item.field.setStyle('display', 'block');
}
else
{
item.field.setStyle('display', 'none');
}
});
});
});
},
/**
* Generate a set of tabs of which the content for each tab will be loaded
* using an Ajax request. By default the content of these tabs will be inserted
* after the element that contains the tabs. This content will be inserted into
* a div of which the class is "tab_content".
*
* @author Yorick Peterse
* @since 0.1
* @return {void}
*/
ajaxTabs: function()
{
// Create a reference to the current instance so we can
// use data in this instance in our events and loops.
var self = this;
// Select our default tab element
var default_link = this.element.getElement(self.options['default']).getElement('a');
var links = this.element.getElements('li a');
// Create the element that will contain our Ajax response data
tab_content = new Element('div', {'class': 'tab_content'});
tab_content.inject(this.element, 'after');
// Load our default tab content
this.element.getElement(self.options['default']).addClass('active');
this.element.getNext('.tab_content').load(default_link.get('href'));
links.each(function(link)
{
// Add an event that will show the corresponding field for each link
link.addEvent('click', function(event)
{
// Prevent normal behavior
event.stop();
self.element.getElement('li.active').removeClass('active');
// Now we can add the class to the current tab
this.getParent('li').addClass('active');
self.element.getNext('.tab_content').load(this.get('href'));
});
});
}
});