Created
April 3, 2014 00:38
-
-
Save onestepcreative/9946174 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Author: Josh McDonald | |
Twitter: @onestepcreative | |
Website: developerstoolbox.net | |
Version: 2.0.1 | |
This plugin allows for you to define your | |
tabs, and your tab content by simple selectors. | |
The script then assigns a matching index to each | |
tab and content selector, for easy cookie storage | |
later. So tab one and tabContent one will both | |
be assigned data-index="1", thus being able | |
to link up each tab to its corresponding | |
tab content. | |
This plugin requires jQuery Cookies to | |
take advantage of active tab saving. | |
Download Cookies: https://github.com/carhartl/jquery-cookie | |
*/ | |
;(function($, window, document, undefined) { | |
'use strict'; | |
CrystalCore.libs.tably = { | |
name : 'tably', | |
version : '2.0.1', | |
init : function(scope, settings) { | |
// kick off the plugin | |
new Tably(scope, settings); | |
// handle parameters passed | |
} | |
}; | |
var Tably = function(scope, settings) { | |
var self = this; | |
var scope = $(scope); | |
// Default Tably Options | |
self.options = { | |
// Define tablys scope | |
scoped : scope, | |
// Tab settings | |
trigger : '.tab-trigger', | |
panel : '.tab-panel', | |
active : 'active', | |
effect : 'fade', | |
start : 3, | |
// Tably's Loader Settings | |
loader : 'stretch', | |
speed : 'medium', | |
// Cookie settings | |
save : true, | |
name : 'active_tab', | |
path : '/', | |
time : 7, | |
// Editable Ajaxify options for Tably | |
ajaxify : { | |
// default ajax options | |
data : null, | |
type : 'GET', | |
dataType : 'html', | |
// callbacks to handle data | |
before : null, | |
success : null, | |
failure : null, | |
// local storage options | |
cached : false, | |
key : settings.url, | |
duration : 3, | |
// data cleaning options | |
clean : { | |
links : true, | |
images : true | |
} | |
} | |
}, | |
$.extend(true, self.options, settings); | |
self.init = function() { | |
self.loader.build(); | |
self.build.init() | |
self.events.bind(); | |
}, | |
self.build = { | |
init: function() { | |
self.build.tabs(); | |
self.build.panels(); | |
self.build.setActive(); | |
}, | |
tabs: function() { | |
// Find all tabs within plugin scope | |
var tabs = self.get.tabs; | |
// Setup index for looping over tabs | |
var indx = 0; | |
// Loop through tabs and create markup | |
$(tabs).each(function(indx) { | |
// Cache single tab to variable | |
var tab = $(this); | |
// Add data-index to tab element | |
tab.attr('data-index', indx + 1); | |
}); | |
// Determine + show the active | |
//self.markup.activate(); | |
}, | |
panels: function() { | |
// Find all panels within plugin scope | |
var panels = self.get.panels; | |
// Setup index for looping over panels | |
var indx = 0; | |
// Loop through panels and create markup | |
$(panels).each(function(indx) { | |
// Cache single tab to variable | |
var panel = $(this); | |
// Add data-index to panel element | |
panel.attr('data-index', indx + 1); | |
// If fade effect is on, add fade classes | |
if(self.options.effect === 'fade') { | |
panel.addClass('fade out'); | |
} | |
}); | |
}, | |
setActive: function() { | |
// A var to store active index info | |
var activeIndex; | |
// If cookies are enabled and a cookie value already exists | |
if(self.options.save && self.cookies.get(self.options.name)) { | |
// Set value of active from the cookie value stored | |
activeIndex = self.cookies.get(self.options.name); | |
// If a start position was defined in the plugin settings | |
} else if(self.options.start && self.options.start > 0) { | |
// Set value of active based on 'start' setting | |
activeIndex = self.options.start; | |
// If no overrides exist, just show the first tab + panel by default | |
} else { | |
// If no condition match from above, show first tab + panel by default | |
activeIndex = 1; | |
} | |
// Set new active tab based on the activeIndex generated from above | |
var tab = scope.find(self.options.trigger + '[data-index="' + activeIndex + '"]'); | |
// The matching panel of clicked tab | |
var panel = self.get.match(tab); | |
// Check to see if tab is to use Ajaxify | |
var ajaxify = self.AjaxifyTab(tab); | |
// Add active class to the activeIndex tab | |
tab.addClass(self.options.active); | |
// Add active class to tab's matching panel | |
panel.addClass(self.options.active); | |
// If this is an ajax tab | |
if(ajaxify && !self.get.match(tab).attr('data-ajaxified')) { | |
ajaxify.init(); | |
} | |
}, | |
}, | |
self.get = { | |
tabs: (function() { | |
// Returns jQuery array of all tabs within scope | |
return (scope.find(self.options.trigger)); | |
}()), | |
panels: (function() { | |
// Returns jQuery array of all panels within scope | |
return (scope.find(self.options.panel)); | |
}()), | |
indx: function(elem) { | |
// Gets the data-indx value of passed in tab | |
return elem.attr('data-index'); | |
}, | |
match: function(tab) { | |
// Returns the corresponding tab panel, for tab that is passed in | |
return scope.find(self.options.panel + '[data-index="' + tab.attr('data-index') + '"]'); | |
}, | |
}, | |
self.loader = { | |
init: function() { | |
// Exit function if loader setting is turned off | |
if(self.options.loader === null) { return; } | |
// Make sure loader setting is a 'string' | |
if(self.options.loader === 'string') { | |
self.loader.build(); | |
} | |
}, | |
build: function() { | |
// This function creates the html markup for the loading indicator | |
// The parent container for the loader | |
var markup = '<div class="tably-loader loader hide">'; | |
var i = 1; | |
// Add six children to parent, so we have something to animate | |
for(i; i < 6; i++) { markup += '<div class="c' + i + '"></div>'; } | |
// Close the parent container | |
markup += '</div>'; | |
// Turn markup into jQuery object | |
var loader = $(markup); | |
// Add effect & speed classes to loader | |
self.loader.effects(loader); | |
// Add loader to the top of the scope container | |
scope.prepend(loader); | |
}, | |
effects: function(loader) { | |
// Assigns classes based on effect & speed | |
// Get animation effect from plugin settings | |
var effect = self.options.loader; | |
// Get animation speed from plugin settings | |
var speed = self.options.speed; | |
// Add loader effect class | |
switch(effect) { | |
case 'stretch': | |
loader.addClass('stretch'); | |
break; | |
case 'worm' : | |
loader.addClass('worm'); | |
break; | |
case 'bar' : | |
loader.addClass('bar'); | |
break; | |
default : | |
loader.addClass('bar'); | |
break; | |
} | |
// Add speed effect class | |
switch(speed) { | |
case 'slow': | |
loader.addClass('slow'); | |
break; | |
case 'medium' : | |
loader.addClass('medium'); | |
break; | |
case 'fast' : | |
loader.addClass('fast'); | |
break; | |
default : | |
loader.addClass('medium'); | |
break; | |
} | |
}, | |
show: function() { | |
// Assign loader to a var for perf | |
var loader = scope.find('.tably-loader'); | |
// Fadeout loader and add 'hide' class | |
loader.fadeIn(500).removeClass('hide'); | |
}, | |
hide: function() { | |
// Assign loader to a var for perf | |
var loader = scope.find('.tably-loader'); | |
// Fadeout loader and add 'hide' class | |
loader.fadeOut(250).addClass('hide'); | |
}, | |
}, | |
self.cookies = { | |
opts: { expires: self.options.time, path: self.options.path }, | |
get: function(name) { | |
return $.cookie(name); | |
}, | |
set: function(name, value) { | |
// If cookies are enabled | |
if(!self.options.save) { return; } | |
// If the cookie already exists with value | |
if(self.cookies.get(name)) { | |
// Update the value of the cookie | |
self.cookies.update(name, value); | |
} else { | |
// If no cookie exists, create a new one | |
self.cookies.create(name, value, self.cookies.opts); | |
} | |
}, | |
create: function(name, value) { | |
// Create new cookie from clicked tab | |
$.cookie(name, value, self.cookies.opts); | |
}, | |
update: function(name, value) { | |
// Update cookie value | |
$.cookie(name, value); | |
}, | |
destroy: function(name, opts) { | |
$.removeCookie(name, opts); | |
} | |
}, | |
self.events = { | |
bind: function() { | |
// Add a new event listener to all tabs | |
//self.get.tabs.on('click', self.events.open); | |
scope.on('click.ajaxify', '.tab-trigger', self.events.open); | |
}, | |
open: function(e) { | |
// If clicked tab is already active, exit function | |
if($(this).hasClass(self.options.active)) { return; } | |
// Prevent default action | |
e.preventDefault(); | |
// Get the tab that was active before click | |
var active = scope.find(self.options.trigger + '.' + self.options.active); | |
// The tab that was clicked | |
var tab = $(this); | |
// The matching panel of clicked tab | |
var panel = self.get.match(tab); | |
// Get the data indx for the clicked tab | |
var indx = self.get.indx(tab); | |
// Checks if tab has Ajaxify content | |
var ajaxify = self.AjaxifyTab(tab); | |
// Close the current active tab | |
self.events.close(active); | |
// Update cookie value if it exists, or create cookie if it doesn't | |
self.cookies.set(self.options.name, self.get.indx(tab)); | |
// If an ajax tab, and tab doesn't have it's content | |
if(ajaxify && !self.get.match(tab).attr('data-ajaxified')) { | |
ajaxify.init(); | |
} | |
// Add active class to tab just clicked | |
tab.addClass(self.options.active); | |
// If fade option is set in scope settings | |
if(self.options.effect === 'fade') { | |
// Remove the 'fade out' class | |
panel.removeClass('out') | |
} | |
// Add active class to tabs matching panel | |
panel.addClass(self.options.active); | |
// Trigger the open event for active tab | |
scope.trigger('open.tably.tab_' + indx); | |
//scope.trigger('open.tably.tab', ['tab_' + indx]); | |
}, | |
close: function(tab) { | |
var indx = self.get.indx(tab); | |
var panel = self.get.match(tab); | |
// Remove active class the tab passed in | |
tab.removeClass(self.options.active); | |
// Remove active class passed tab's matching panel | |
panel.removeClass(self.options.active); | |
// If fade option is set in scope settings | |
if(self.options.effect === 'fade') { | |
// Add the 'fade out' class | |
panel.addClass('out'); | |
} | |
// Trigger the close event for tab passed in | |
scope.trigger('close.tably.tab_' + indx); | |
//scope.trigger('close.tably.tab', ['tab_' + indx]); | |
}, | |
listeners: function() { | |
// This function sets up event listeners on the | |
// window for various plugins and functionality, | |
// and fires callbacks when the events are detected | |
// If ajaxify returns an empty response, hide loader | |
$(window).on('ajaxify.responseError', self.callbacks.responseError); | |
// When ajax is done, and is on the page, remove loader | |
$(window).on('ajaxify.contentParsed', self.loader.hide); | |
} | |
}, | |
self.callbacks = { | |
responseError: function(event, data) { | |
dev.error('ajaxify error', data); | |
// Build alert message from error data received | |
var alert = $('<span class="ajaxify-error">' + data.msg + '</span>'); | |
// Find the active tab panel that made the request | |
var panel = scope.find(self.options.panel + '.' + self.options.active); | |
// Show alert in active panel | |
panel.append(alert); | |
// Add the ajax 'flag' | |
panel.attr('data-ajaxified', 'true'); | |
}, | |
}, | |
// =========================================================================== | |
// ===== Function only called when a tab is using Ajaxify for dynamic content | |
// =========================================================================== | |
self.AjaxifyTab = function(tab) { | |
/* | |
This function, using the 'Reveal Module Pattern' defines the | |
functionality for tabs loading ajax content. If conditions are | |
met in the 'self.events.select' function, this function returns | |
a nicely packaged object consisting of all ajaxify settings that | |
are needed in order to work in the Tably implementation. | |
@param tab - (string) the tab that was clicked on | |
*/ | |
var init = function() { | |
/* | |
In order for this init function to run, which | |
will make an ajax request using the Ajaxify Plugin, it | |
must first meet two conditions in the 'self.events.selector' | |
function. The 'self.events.selector' is an event callback | |
that is fired when a tab is clicked, | |
1. The tab clicked must have the url store in a 'data-ajaxify-url' attr | |
2. The tab's matching content panel cannot have a 'data-ajaxified' attr | |
*/ | |
// Indicate that something is loading to the user | |
self.loader.show(); | |
// Initialize Ajaxify Plugin to make ajax request | |
$(document).crystalcore('ajaxify', { | |
// Dynamically set from tab markup | |
scoped : this.scoped, | |
url : this.url, | |
elem : this.elem, | |
parsed : this.parsed, | |
// Explicitly set to work best with Tably | |
loader : null, | |
speed : null, | |
replace : false, | |
effect : self.options.effect, | |
// Default ajax options | |
data : self.options.ajaxify.data, | |
type : self.options.ajaxify.type, | |
dataType : self.options.ajaxify.dataType, | |
// callbacks to handle data | |
before : self.options.ajaxify.before, | |
success : self.options.ajaxify.success, | |
failure : self.options.ajaxify.failure, | |
// local storage options | |
cached : self.options.ajaxify.cached, | |
key : self.options.ajaxify.key, | |
duration : self.options.ajaxify.duration, | |
// data cleaning options | |
clean : { | |
links : self.options.ajaxify.links, | |
images : self.options.ajaxify.images | |
} | |
}); | |
} | |
// If the tab is setup with a ajax url | |
if(tab.attr('data-ajaxify-url')) { | |
// Check if content has already been loaded to this tab | |
var parsedFlag = self.get.match(tab).attr('data-ajaxified') || false; | |
// Get the ajaxify url from data attr | |
var requestUrl = tab.attr('data-ajaxify-url'); | |
// The class for ajax data to be injected in to | |
var appendClass = tab.attr('data-ajaxify-class'); | |
// Return an object with required settings for ajax | |
return { | |
flag : parsedFlag, | |
scoped : scope, | |
url : requestUrl, | |
elem : appendClass, | |
init : init | |
}; | |
} | |
return false; | |
} | |
// Kick off init func | |
self.init(); | |
// Global event listeners | |
self.events.listeners(); | |
}; | |
})(jQuery, this, this.document); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment