/** * Zebra_Form * * Client-side validation for Zebra_Form * * Visit {@link http://stefangabos.ro/php-libraries/zebra-form/} for more information. * * For more resources visit {@link http://stefangabos.ro/} * * @author Stefan Gabos * @version 2.9.4 (last revision: November 20, 2013) * @copyright (c) 2011 - 2013 Stefan Gabos * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LESSER GENERAL PUBLIC LICENSE * @package Zebra_Form */ (function($) { $.Zebra_Form = function(element, options) { var plugin = this; // public properties var defaults = { scroll_to_error: true, tips_position: 'left', close_tips: true, validate_on_the_fly: false, validate_all: false, assets_path: null } plugin.settings = {} // private properties var validation_rules = new Object, controls_groups = new Object, error_blocks = new Object, placeholders = new Array, proxies = new Object, proxies_cache = new Object, reload = false, validated = false, browser, elements; // the jQuery version of the element // "form" (without the $) will point to the DOM element var $form = $(element), form = element; // code by Joyce Babu // found at http://www.weberdev.com/get_example-4437.html plugin.filter_input = function(filter_type, evt, custom_chars) { var key_code, key, control, filter = ''; var alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; var digits = '0123456789'; if (window.event) { key_code = window.event.keyCode; evt = window.event; } else if (evt) key_code = evt.which; else return true; switch (filter_type) { case 'alphabet': filter = alphabet; break; case 'digits': case 'number': case 'float': filter = digits; break; case 'alphanumeric': filter = alphabet + digits; break; default: return true; } if (custom_chars) { filter += custom_chars } control = evt.srcElement ? evt.srcElement : evt.target || evt.currentTarget; if (key_code==null || key_code==0 || key_code==8 || key_code==9 || key_code==13 || key_code==27) return true; key = String.fromCharCode(key_code); if ((key=='v' || key=='a' || key=='c' || key=='x') && evt.ctrlKey) return true; if (filter.indexOf(key) > -1) return true; if (filter_type == 'number' && key == '-' && _get_caret_position(control) == 0) return true; if (filter_type == 'float' && ((key == '-' && _get_caret_position(control) == 0) || (key == '.' && _get_caret_position(control) != 0 && control.value.match(/\./) == null))) return true; return false; } /** * Constructor method * * @return void */ plugin.init = function() { plugin.settings = $.extend({}, defaults, options); // find all dummy options and remove them from the DOM // we need them"dummy options" to create valid HTML/XHTML output because empty option groups are not // allowed; unfortunately, IE does not support neither the "disabled" attribute nor styling these // empty options so we need to remove them from the DOM $form.find('option.dummy').remove(); // find any error blocks generated by the server-side script and iterate through them $('div.error', $form).each(function() { // attach a function to the error block's "close" button $('div.close a', $(this)).bind('click', function(e) { e.preventDefault(); // morph the error block's height and opacity to 0 $(this).closest('div.error').animate({ 'height' : 0, 'opacity' : 0 }, 250, function() { // remove from DOM when done $(this).remove(); }); }); }); // get all the form's elements elements = $('.control', $form); // iterate through the form's elements elements.each(function() { var element = $(this), // get some attributes of the element attributes = {'id': element.attr('id'), 'name': element.attr('name'), 'type': _type(element)}, // in order to highlight the row that the element is in // get the parent element having the "row" class set parent = element.closest('.row'); // if element also has the "name" attribute // (some plugins copy the original element's classes and Zebra_Form will falsely belive they are form elements // once it gets to them) if (undefined != attributes['name']) // sanitize element's name by removing square brackets (if available) attributes['name'] = attributes['name'].replace(/\[\]$/, ''); // if a parent element having the "row" class exists if (parent.length) // bind these events to the element element.bind({ // when the element receives focus // add the "highlight" class to the parent element 'focus': function() { parent.addClass('highlight') }, // when the element receives focus // remove the "highlight" class from the parent element 'blur': function() { parent.removeClass('highlight') } }); if ( // if element has the "inside" class set // meaning that the element's label needs to be shown inside the element, until the element receives focus (element.hasClass('inside') && ( // the class is applied to an allowed element type attributes['type'] == 'text' || attributes['type'] == 'password' || attributes['type'] == 'textarea' )) || // or element has a character counter attached element.hasClass('show-character-counter') || // element is "text" or "password" and has the "prefix" data attribute set ((attributes['type'] == 'text' || attributes['type'] == 'password') && element.data('prefix')) ) { // we create a wrapper for the parent element so that we can later position the // placeholder, prefix or characer counter // also, make sure the wrapper inherits some important css properties of the parent element var element_wrapper = jQuery('').css({ 'display': element.css('display'), 'position': element.css('position') == 'static' ? 'relative' : element.css('position'), 'float': element.css('float'), 'top': element.css('top'), 'right': element.css('right'), 'bottom': element.css('bottom'), 'left': element.css('left') }); // replace the parent element with the wrapper and then place it inside the wrapper // also, make sure we set some important css properties for it element = element.replaceWith(element_wrapper).css({ 'position': 'relative', 'top': 'auto', 'right': 'auto', 'bottom': 'auto', 'left': 'auto' }).appendTo(element_wrapper); } if ( // if element has the "inside" class set // meaning that the element's label needs to be shown inside the element, until the element receives focus element.hasClass('inside') && ( // the class is applied to an allowed element type attributes['type'] == 'text' || attributes['type'] == 'password' || attributes['type'] == 'textarea' ) ) { // get element's offset relative to the first positioned parent element var position = element.position(); // if element is a text box or a password if (attributes['type'] == 'text' || attributes['type'] == 'password') // create a text element that will float above the element until the the parent element receives the focus var placeholder = jQuery('').attr({ 'type': 'text', 'class': 'Zebra_Form_Placeholder', 'autocomplete': 'off', 'value': element.attr('title') }); // if element is a textarea else // create a textarea element that will float above the element until the parent element receives the focus var placeholder = jQuery('