/*
* jQuery Custom Forms Plugin 1.0
* www.ZURB.com
* Copyright 2010, ZURB
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*/
(function( $ ){
/**
* Helper object used to quickly adjust all hidden parent element's, display and visibility properties.
* This is currently used for the custom drop downs. When the dropdowns are contained within a reveal modal
* we cannot accurately determine the list-item elements width property, since the modal's display property is set
* to 'none'.
*
* This object will help us work around that problem.
*
* NOTE: This could also be plugin.
*
* @function hiddenFix
*/
var hiddenFix = function() {
return {
/**
* Sets all hidden parent elements and self to visibile.
*
* @method adjust
* @param {jQuery Object} $child
*/
// We'll use this to temporarily store style properties.
tmp : [],
// We'll use this to set hidden parent elements.
hidden : null,
adjust : function( $child ) {
// Internal reference.
var _self = this;
// Set all hidden parent elements, including this element.
_self.hidden = $child.parents().andSelf().filter( ":hidden" );
// Loop through all hidden elements.
_self.hidden.each( function() {
// Cache the element.
var $elem = $( this );
// Store the style attribute.
// Undefined if element doesn't have a style attribute.
_self.tmp.push( $elem.attr( 'style' ) );
// Set the element's display property to block,
// but ensure it's visibility is hidden.
$elem.css( { 'visibility' : 'hidden', 'display' : 'block' } );
});
}, // end adjust
/**
* Resets the elements previous state.
*
* @method reset
*/
reset : function() {
// Internal reference.
var _self = this;
// Loop through our hidden element collection.
_self.hidden.each( function( i ) {
// Cache this element.
var $elem = $( this ),
_tmp = _self.tmp[ i ]; // Get the stored 'style' value for this element.
// If the stored value is undefined.
if( _tmp === undefined )
// Remove the style attribute.
$elem.removeAttr( 'style' );
else
// Otherwise, reset the element style attribute.
$elem.attr( 'style', _tmp );
});
// Reset the tmp array.
_self.tmp = [];
// Reset the hidden elements variable.
_self.hidden = null;
} // end reset
}; // end return
};
jQuery.foundation = jQuery.foundation || {};
jQuery.foundation.customForms = jQuery.foundation.customForms || {};
$.foundation.customForms.appendCustomMarkup = function ( options ) {
var defaults = {
disable_class: "js-disable-custom"
};
options = $.extend( defaults, options );
function appendCustomMarkup(idx, sel) {
var $this = $(sel).hide(),
type = $this.attr('type'),
$span = $this.next('span.custom.' + type);
if ($span.length === 0) {
$span = $(' ').insertAfter($this);
}
$span.toggleClass('checked', $this.is(':checked'));
$span.toggleClass('disabled', $this.is(':disabled'));
}
function appendCustomSelect(idx, sel) {
var hiddenFixObj = hiddenFix();
//
// jQueryify the element and cache it.
//
var $this = $( sel ),
//
// Find the custom drop down element.
//
$customSelect = $this.next( 'div.custom.dropdown' ),
//
// Find the custom select element within the custom drop down.
//
$customList = $customSelect.find( 'ul' ),
//
// Find the custom a.current element.
//
$selectCurrent = $customSelect.find( ".current" ),
//
// Find the custom a.selector element (the drop-down icon).
//
$selector = $customSelect.find( ".selector" ),
//
// Get the from the element.
//
$options = $this.find( 'option' ),
//
// Filter down the selected options
//
$selectedOption = $options.filter( ':selected' ),
//
// Initial max width.
//
maxWidth = 0,
//
// We'll use this variable to create the elements for our custom select.
//
liHtml = '',
//
// We'll use this to cache the created elements within our custom select.
//
$listItems
;
var $currentSelect = false;
//
// Should we not create a custom list?
//
if ( $this.hasClass( 'no-custom' ) ) return;
//
// Did we not create a custom select element yet?
//
if ( $customSelect.length === 0 ) {
//
// Let's create our custom select element!
//
//
// Determine what select size to use.
//
var customSelectSize = $this.hasClass( 'small' ) ? 'small' :
$this.hasClass( 'medium' ) ? 'medium' :
$this.hasClass( 'large' ) ? 'large' :
$this.hasClass( 'expand' ) ? 'expand' : ''
;
//
// Build our custom list.
//
$customSelect = $('"');
//
// Grab the selector element
//
$selector = $customSelect.find( ".selector" );
//
// Grab the unordered list element from the custom list.
//
$customList = $customSelect.find( "ul" );
//
// Build our elements.
//
liHtml = $options.map( function() { return " " + $( this ).html() + " "; } ).get().join( '' );
//
// Append our elements to the custom list ().
//
$customList.append( liHtml );
//
// Insert the the currently selected list item before all other elements.
// Then, find the element and assign it to $currentSelect.
//
$currentSelect = $customSelect.prepend( '' + $selectedOption.html() + ' ' ).find( ".current" );
//
// Add the custom select element after the element.
//
$this.after( $customSelect )
//
//then hide the element.
//
.hide();
} else {
//
// Create our list item elements.
//
liHtml = $options.map( function() { return " " + $( this ).html() + " "; } ).get().join( '' );
//
// Refresh the ul with options from the select in case the supplied markup doesn't match.
// Clear what's currently in the element.
//
$customList.html( '' )
//
// Populate the list item elements.
//
.append( liHtml );
} // endif $customSelect.length === 0
//
// Determine whether or not the custom select element should be disabled.
//
$customSelect.toggleClass( 'disabled', $this.is( ':disabled' ) );
//
// Cache our List item elements.
//
$listItems = $customList.find( 'li' );
//
// Determine which elements to select in our custom list.
//
$options.each( function ( index ) {
if ( this.selected ) {
//
// Add the selected class to the current li element
//
$listItems.eq( index ).addClass( 'selected' );
//
// Update the current element with the option value.
//
if ($currentSelect) {
$currentSelect.html( $( this ).html() );
}
}
});
//
// Update the custom list width property.
//
$customList.css( 'width', 'inherit' );
//
// Set the custom select width property.
//
$customSelect.css( 'width', 'inherit' );
//
// If we're not specifying a predetermined form size.
//
if ( !$customSelect.is( '.small, .medium, .large, .expand' ) ) {
// ------------------------------------------------------------------------------------
// This is a work-around for when elements are contained within hidden parents.
// For example, when custom-form elements are inside of a hidden reveal modal.
//
// We need to display the current custom list element as well as hidden parent elements
// in order to properly calculate the list item element's width property.
// -------------------------------------------------------------------------------------
//
// Show the drop down.
// This should ensure that the list item's width values are properly calculated.
//
$customSelect.addClass( 'open' );
//
// Quickly, display all parent elements.
// This should help us calcualate the width of the list item's within the drop down.
//
hiddenFixObj.adjust( $customList );
//
// Grab the largest list item width.
//
maxWidth = ( $listItems.outerWidth() > maxWidth ) ? $listItems.outerWidth() : maxWidth;
//
// Okay, now reset the parent elements.
// This will hide them again.
//
hiddenFixObj.reset();
//
// Finally, hide the drop down.
//
$customSelect.removeClass( 'open' );
//
// Set the custom list width.
//
$customSelect.width( maxWidth + 18);
//
// Set the custom list element () width.
//
$customList.width( maxWidth + 16 );
} // endif
}
$('form.custom input:radio[data-customforms!=disabled]').each(appendCustomMarkup);
$('form.custom input:checkbox[data-customforms!=disabled]').each(appendCustomMarkup);
$('form.custom select[data-customforms!=disabled]').each(appendCustomSelect);
};
var refreshCustomSelect = function($select) {
var maxWidth = 0,
$customSelect = $select.next();
$options = $select.find('option');
$customSelect.find('ul').html('');
$options.each(function () {
$li = $('' + $(this).html() + ' ');
$customSelect.find('ul').append($li);
});
// re-populate
$options.each(function (index) {
if (this.selected) {
$customSelect.find('li').eq(index).addClass('selected');
$customSelect.find('.current').html($(this).html());
}
});
// fix width
$customSelect.removeAttr('style')
.find('ul').removeAttr('style');
$customSelect.find('li').each(function () {
$customSelect.addClass('open');
if ($(this).outerWidth() > maxWidth) {
maxWidth = $(this).outerWidth();
}
$customSelect.removeClass('open');
});
$customSelect.css('width', maxWidth + 18 + 'px');
$customSelect.find('ul').css('width', maxWidth + 16 + 'px');
};
var toggleCheckbox = function($element) {
var $input = $element.prev(),
input = $input[0];
if (false === $input.is(':disabled')) {
input.checked = ((input.checked) ? false : true);
$element.toggleClass('checked');
$input.trigger('change');
}
};
var toggleRadio = function($element) {
var $input = $element.prev(),
input = $input[0];
if (false === $input.is(':disabled')) {
$('input:radio[name="' + $input.attr('name') + '"]').next().not($element).removeClass('checked');
if ($element.hasClass('checked')) {
// Do Nothing
} else {
$element.toggleClass('checked');
}
input.checked = $element.hasClass('checked');
$input.trigger('change');
}
};
$(document).on('click', 'form.custom span.custom.checkbox', function (event) {
event.preventDefault();
event.stopPropagation();
toggleCheckbox($(this));
});
$(document).on('click', 'form.custom span.custom.radio', function (event) {
event.preventDefault();
event.stopPropagation();
toggleRadio($(this));
});
$(document).on('change', 'form.custom select[data-customforms!=disabled]', function (event) {
refreshCustomSelect($(this));
});
$(document).on('click', 'form.custom label', function (event) {
var $associatedElement = $('#' + $(this).attr('for')),
$customCheckbox,
$customRadio;
if ($associatedElement.length !== 0) {
if ($associatedElement.attr('type') === 'checkbox') {
event.preventDefault();
$customCheckbox = $(this).find('span.custom.checkbox');
toggleCheckbox($customCheckbox);
} else if ($associatedElement.attr('type') === 'radio') {
event.preventDefault();
$customRadio = $(this).find('span.custom.radio');
toggleRadio($customRadio);
}
}
});
$(document).on('click', 'form.custom div.custom.dropdown a.current, form.custom div.custom.dropdown a.selector', function (event) {
var $this = $(this),
$dropdown = $this.closest('div.custom.dropdown'),
$select = $dropdown.prev();
event.preventDefault();
$('div.dropdown').removeClass('open');
if (false === $select.is(':disabled')) {
$dropdown.toggleClass('open');
if ($dropdown.hasClass('open')) {
$(document).bind('click.customdropdown', function (event) {
$dropdown.removeClass('open');
$(document).unbind('.customdropdown');
});
} else {
$(document).unbind('.customdropdown');
}
return false;
}
});
$(document).on('click', 'form.custom div.custom.dropdown li', function (event) {
var $this = $(this),
$customDropdown = $this.closest('div.custom.dropdown'),
$select = $customDropdown.prev(),
selectedIndex = 0;
event.preventDefault();
event.stopPropagation();
$('div.dropdown').removeClass('open');
$this
.closest('ul')
.find('li')
.removeClass('selected');
$this.addClass('selected');
$customDropdown
.removeClass('open')
.find('a.current')
.html($this.html());
$this.closest('ul').find('li').each(function (index) {
if ($this[0] == this) {
selectedIndex = index;
}
});
$select[0].selectedIndex = selectedIndex;
$select.trigger('change');
});
$.fn.foundationCustomForms = $.foundation.customForms.appendCustomMarkup;
})( jQuery );