/* Gumby JS */
(function ($) {
var Gumby = function () {
// Gumby data object for storing simpleUI classes and handlers
var gumbyData = {},
setGumbyData = function (key, value) {
return gumbyData[key] = value;
},
getGumbyData = function (key) {
return gumbyData[key] || false;
},
/**
* Simple UI Elements
* ------------------
* UI elements that bind to an event, toggle
* a class with possibility to run simple logic
* on completion and test for specific conditions
*/
simpleUI = {
// simple UI elements holder object
ui: [
// checkbox - check/uncheck (including hidden input) on click
{
selector: '.checkbox',
onEvent: 'click',
className: 'checked',
target: false,
condition: false,
// check/uncheck hidden checkbox input
complete: function ($e) {
var checked = $e.hasClass('checked');
$e.children('input').attr('checked', checked);
}
},
// radio - check/uncheck (including hidden input) on click
// also uncheck all others with same name
{
selector: '.radio',
onEvent: 'click',
className: 'checked',
target: false,
condition: false,
// check hidden radio input and uncheck others
complete: function ($e) {
var $input = $e.children('input'),
// radio buttons with matching names in the same group
$otherInputs = $('input[name="' + $input.attr('name') + '"]');
// ensure other radio buttons are not checked
$otherInputs.attr('checked', false).parent().removeClass('checked');
// check this one
$input.attr('checked', true).parent().addClass('checked');
}
},
// validation - add/remove error class dependent on value being present
// conditional method used to check for value
{
selector: 'form[data-form="validate"] .field',
onEvent: 'blur',
className: 'error',
target: false,
// check input is required and if so add/remove error class based on present value
condition: function ($e) {
var $child = $e.find('input, textarea').first(),
val = $child.val();
if(!$child.attr('required')) {
return false;
}
// email/regular validation
if (($child.attr('type') === 'email' && !val.match(/^[\w.%&=+$#!-']+@[\w.-]+\.[a-zA-Z]{2,4}$/)) || !val.length) {
$e.addClass('error');
return false;
}
$e.removeClass('error');
},
complete: false
},
// toggles - toggle active class on itself and selector in data-for
// on click
{
selector: '.toggle:not([data-on]), .toggle[data-on="click"]',
onEvent: 'click',
className: 'active',
target: function($e) {
return $e.add($($e.attr('data-for')));
},
condition: false,
complete: false
},
// on mouseover (will always add class) and mouseout (will always remove class)
{
selector: '.toggle[data-on="hover"]',
onEvent: 'mouseover mouseout',
className: 'active',
target: function($e) {
return $e.add($($e.attr('data-for')));
},
condition: false,
complete: false
}
],
// initialize simple UI
init: function () {
var x, ui, $e, callBack, conditionalCallBack, activeClass, targetName;
// loop round gumby UI elements applying active/inactive class logic
for (x in simpleUI.ui) {
ui = simpleUI.ui[x];
$e = $(ui.selector);
// complete call back
callBack = ui.complete && typeof ui.complete === 'function' ? ui.complete : false;
// conditional callback
conditionalCallBack = ui.condition && typeof ui.condition === 'function' ? ui.condition : false;
targetName = ui.target && typeof ui.target === 'function' ? ui.target : false;
activeClass = ui.className || false;
// store UI data
// replace spaces with dashes for GumbyData object reference
setGumbyData(ui.selector.replace(' ', '-'), {
'GumbyCallback' : callBack,
'GumbyConditionalCallBack' : conditionalCallBack,
'GumbyActiveClass' : activeClass,
'GumbyTarget' : targetName
});
// bind it all!
$(document).on(ui.onEvent, ui.selector, function (e) {
e.preventDefault();
var $this = $(this),
$target = $(this),
gumbyData = getGumbyData(e.handleObj.selector.replace(' ', '-')),
condition = true;
// if there is a conditional function test it here
// leaving if it returns false
if(gumbyData.GumbyConditionalCallBack) {
return condition = gumbyData.GumbyConditionalCallBack($this);
}
// no conditional or it passed so toggle class
if (gumbyData.GumbyActiveClass) {
// check for sepcified target
if(gumbyData.GumbyTarget) {
$target = gumbyData.GumbyTarget($this);
}
$target.toggleClass(gumbyData.GumbyActiveClass);
}
// if complete call back present call it here
if (gumbyData.GumbyCallback) {
gumbyData.GumbyCallback($this);
}
});
}
}
},
/**
* Complex UI Elements
* ------------------
* UI elements that require logic passed the
* capabilities of simple add/remove class.
*/
complexUI = {
// init separate complexUI elements
init: function () {
complexUI.pickers();
complexUI.skipLinks();
complexUI.tabs();
},
// pickers - open picker on click and update