Subversion Repositories wpShopGermany4

Rev

Rev 2955 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Inline Form Validation Engine 2.6.2, jQuery plugin
 *
 * Copyright(c) 2010, Cedric Dugas
 * http://www.position-absolute.com
 *
 * 2.0 Rewrite by Olivier Refalo
 * http://www.crionics.com
 *
 * Form validation engine allowing custom regex rules to be added.
 * Licensed under the MIT License
 */
 (function($) {

        "use strict";

        var methods = {

                /**
                * Kind of the constructor, called before any action
                * @param {Map} user options
                */
                init: function(options) {
                        var form = this;
                        if (!form.data('jqv') || form.data('jqv') == null ) {
                                options = methods._saveOptions(form, options);
                                // bind all formError elements to close on click
                                $(document).on("click", ".formError", function() {                                      
                                        $(this).fadeOut(150, function() {
                                                // remove prompt once invisible
                                                $(this).parent('.formErrorOuter').remove();
                                                $(this).remove();
                                        });
                                });
                        }
                        return this;
                 },
                /**
                * Attachs jQuery.validationEngine to form.submit and field.blur events
                * Takes an optional params: a list of options
                * ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"});
                */
                attach: function(userOptions) {

                        var form = this;
                        var options;

                        if(userOptions)
                                options = methods._saveOptions(form, userOptions);
                        else
                                options = form.data('jqv');

                        options.validateAttribute = (form.find("[data-validation-engine*=validate]").length) ? "data-validation-engine" : "class";
                        if (options.binded) {

                                // delegate fields
                                form.on(options.validationEventTrigger, "["+options.validateAttribute+"*=validate]:not([type=checkbox]):not([type=radio]):not(.datepicker)", methods._onFieldEvent);
                                form.on("click", "["+options.validateAttribute+"*=validate][type=checkbox],["+options.validateAttribute+"*=validate][type=radio]", methods._onFieldEvent);
                                form.on(options.validationEventTrigger,"["+options.validateAttribute+"*=validate][class*=datepicker]", {"delay": 300}, methods._onFieldEvent);
                        }
                        if (options.autoPositionUpdate) {
                                $(window).bind("resize", {
                                        "noAnimation": true,
                                        "formElem": form
                                }, methods.updatePromptsPosition);
                        }
                        form.on("click","a[data-validation-engine-skip], a[class*='validate-skip'], button[data-validation-engine-skip], button[class*='validate-skip'], input[data-validation-engine-skip], input[class*='validate-skip']", methods._submitButtonClick);
                        form.removeData('jqv_submitButton');

                        // bind form.submit
                        form.on("submit", methods._onSubmitEvent);
                        return this;
                },
                /**
                * Unregisters any bindings that may point to jQuery.validaitonEngine
                */
                detach: function() {

                        var form = this;
                        var options = form.data('jqv');

                        // unbind fields
                        form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").off(options.validationEventTrigger, methods._onFieldEvent);
                        form.find("["+options.validateAttribute+"*=validate][type=checkbox],[class*=validate][type=radio]").off("click", methods._onFieldEvent);

                        // unbind form.submit
                        form.off("submit", methods._onSubmitEvent);
                        form.removeData('jqv');
            
                        form.off("click", "a[data-validation-engine-skip], a[class*='validate-skip'], button[data-validation-engine-skip], button[class*='validate-skip'], input[data-validation-engine-skip], input[class*='validate-skip']", methods._submitButtonClick);
                        form.removeData('jqv_submitButton');

                        if (options.autoPositionUpdate)
                                $(window).off("resize", methods.updatePromptsPosition);

                        return this;
                },
                /**
                * Validates either a form or a list of fields, shows prompts accordingly.
                * Note: There is no ajax form validation with this method, only field ajax validation are evaluated
                *
                * @return true if the form validates, false if it fails
                */
                validate: function() {
                        var element = $(this);
                        var valid = null;

                        if (element.is("form") || element.hasClass("validationEngineContainer")) {
                                if (element.hasClass('validating')) {
                                        // form is already validating.
                                        // Should abort old validation and start new one. I don't know how to implement it.
                                        return false;
                                } else {                                
                                        element.addClass('validating');
                                        var options = element.data('jqv');
                                        var valid = methods._validateFields(this);

                                        // If the form doesn't validate, clear the 'validating' class before the user has a chance to submit again
                                        setTimeout(function(){
                                                element.removeClass('validating');
                                        }, 100);
                                        if (valid && options.onSuccess) {
                                                options.onSuccess();
                                        } else if (!valid && options.onFailure) {
                                                options.onFailure();
                                        }
                                }
                        } else if (element.is('form') || element.hasClass('validationEngineContainer')) {
                                element.removeClass('validating');
                        } else {
                                // field validation
                                var form = element.closest('form, .validationEngineContainer'),
                                        options = (form.data('jqv')) ? form.data('jqv') : $.validationEngine.defaults,
                                        valid = methods._validateField(element, options);

                                if (valid && options.onFieldSuccess)
                                        options.onFieldSuccess();
                                else if (options.onFieldFailure && options.InvalidFields.length > 0) {
                                        options.onFieldFailure();
                                }
                        }
                        if(options.onValidationComplete) {
                                // !! ensures that an undefined return is interpreted as return false but allows a onValidationComplete() to possibly return true and have form continue processing
                                return !!options.onValidationComplete(form, valid);
                        }
                        return valid;
                },
                /**
                *  Redraw prompts position, useful when you change the DOM state when validating
                */
                updatePromptsPosition: function(event) {

                        if (event && this == window) {
                                var form = event.data.formElem;
                                var noAnimation = event.data.noAnimation;
                        }
                        else
                                var form = $(this.closest('form, .validationEngineContainer'));

                        var options = form.data('jqv');
                        // No option, take default one
                        form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each(function(){
                                var field = $(this);
                                if (options.prettySelect && field.is(":hidden"))
                                  field = form.find("#" + options.usePrefix + field.attr('id') + options.useSuffix);
                                var prompt = methods._getPrompt(field);
                                var promptText = $(prompt).find(".formErrorContent").html();

                                if(prompt)
                                        methods._updatePrompt(field, $(prompt), promptText, undefined, false, options, noAnimation);
                        });
                        return this;
                },
                /**
                * Displays a prompt on a element.
                * Note that the element needs an id!
                *
                * @param {String} promptText html text to display type
                * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
                * @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight
                */
                showPrompt: function(promptText, type, promptPosition, showArrow) {
                        var form = this.closest('form, .validationEngineContainer');
                        var options = form.data('jqv');
                        // No option, take default one
                        if(!options)
                                options = methods._saveOptions(this, options);
                        if(promptPosition)
                                options.promptPosition=promptPosition;
                        options.showArrow = showArrow==true;

                        methods._showPrompt(this, promptText, type, false, options);
                        return this;
                },
                /**
                * Closes form error prompts, CAN be invidual
                */
                hide: function() {
                         var form = $(this).closest('form, .validationEngineContainer');
                         var options = form.data('jqv');
                         var fadeDuration = (options && options.fadeDuration) ? options.fadeDuration : 0.3;
                         var closingtag;
                         
                         if($(this).is("form") || $(this).hasClass("validationEngineContainer")) {
                                 closingtag = "parentForm"+methods._getClassName($(this).attr("id"));
                         } else {
                                 closingtag = methods._getClassName($(this).attr("id")) +"formError";
                         }
                         $('.'+closingtag).fadeTo(fadeDuration, 0.3, function() {
                                 $(this).parent('.formErrorOuter').remove();
                                 $(this).remove();
                         });
                         return this;
                 },
                 /**
                 * Closes all error prompts on the page
                 */
                 hideAll: function() {

                         var form = this;
                         var options = form.data('jqv');
                         var duration = options ? options.fadeDuration:300;
                         $('.formError').fadeTo(duration, 300, function() {
                                 $(this).parent('.formErrorOuter').remove();
                                 $(this).remove();
                         });
                         return this;
                 },
                /**
                * Typically called when user exists a field using tab or a mouse click, triggers a field
                * validation
                */
                _onFieldEvent: function(event) {
                        var field = $(this);
                        var form = field.closest('form, .validationEngineContainer');
                        var options = form.data('jqv');
                        options.eventTrigger = "field";
                        // validate the current field
                        window.setTimeout(function() {
                                methods._validateField(field, options);
                                if (options.InvalidFields.length == 0 && options.onFieldSuccess) {
                                        options.onFieldSuccess();
                                } else if (options.InvalidFields.length > 0 && options.onFieldFailure) {
                                        options.onFieldFailure();
                                }
                        }, (event.data) ? event.data.delay : 0);

                },
                /**
                * Called when the form is submited, shows prompts accordingly
                *
                * @param {jqObject}
                *            form
                * @return false if form submission needs to be cancelled
                */
                _onSubmitEvent: function() {
                        var form = $(this);
                        var options = form.data('jqv');
                        
                        //check if it is trigger from skipped button
                        if (form.data("jqv_submitButton")){
                                var submitButton = $("#" + form.data("jqv_submitButton"));
                                if (submitButton){
                                        if (submitButton.length > 0){
                                                if (submitButton.hasClass("validate-skip") || submitButton.attr("data-validation-engine-skip") == "true")
                                                        return true;
                                        }
                                }
                        }

                        options.eventTrigger = "submit";

                        // validate each field 
                        // (- skip field ajax validation, not necessary IF we will perform an ajax form validation)
                        var r=methods._validateFields(form);

                        if (r && options.ajaxFormValidation) {
                                methods._validateFormWithAjax(form, options);
                                // cancel form auto-submission - process with async call onAjaxFormComplete
                                return false;
                        }

                        if(options.onValidationComplete) {
                                // !! ensures that an undefined return is interpreted as return false but allows a onValidationComplete() to possibly return true and have form continue processing
                                return !!options.onValidationComplete(form, r);
                        }
                        return r;
                },
                /**
                * Return true if the ajax field validations passed so far
                * @param {Object} options
                * @return true, is all ajax validation passed so far (remember ajax is async)
                */
                _checkAjaxStatus: function(options) {
                        var status = true;
                        $.each(options.ajaxValidCache, function(key, value) {
                                if (!value) {
                                        status = false;
                                        // break the each
                                        return false;
                                }
                        });
                        return status;
                },
                
                /**
                * Return true if the ajax field is validated
                * @param {String} fieldid
                * @param {Object} options
                * @return true, if validation passed, false if false or doesn't exist
                */
                _checkAjaxFieldStatus: function(fieldid, options) {
                        return options.ajaxValidCache[fieldid] == true;
                },
                /**
                * Validates form fields, shows prompts accordingly
                *
                * @param {jqObject}
                *            form
                * @param {skipAjaxFieldValidation}
                *            boolean - when set to true, ajax field validation is skipped, typically used when the submit button is clicked
                *
                * @return true if form is valid, false if not, undefined if ajax form validation is done
                */
                _validateFields: function(form) {
                        var options = form.data('jqv');

                        // this variable is set to true if an error is found
                        var errorFound = false;

                        // Trigger hook, start validation
                        form.trigger("jqv.form.validating");
                        // first, evaluate status of non ajax fields
                        var first_err=null;
                        form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each( function() {
                                var field = $(this);
                                var names = [];
                                if ($.inArray(field.attr('name'), names) < 0) {
                                        errorFound |= methods._validateField(field, options);
                                        if (errorFound && first_err==null)
                                                if (field.is(":hidden") && options.prettySelect)
                                                        first_err = field = form.find("#" + options.usePrefix + methods._jqSelector(field.attr('id')) + options.useSuffix);
                                                else {

                                                        //Check if we need to adjust what element to show the prompt on
                                                        //and and such scroll to instead
                                                        if(field.data('jqv-prompt-at') instanceof jQuery ){
                                                                field = field.data('jqv-prompt-at');
                                                        } else if(field.data('jqv-prompt-at')) {
                                                                field = $(field.data('jqv-prompt-at'));
                                                        }
                                                        first_err=field;
                                                }
                                        if (options.doNotShowAllErrosOnSubmit)
                                                return false;
                                        names.push(field.attr('name'));

                                        //if option set, stop checking validation rules after one error is found
                                        if(options.showOneMessage == true && errorFound){
                                                return false;
                                        }
                                }
                        });

                        // second, check to see if all ajax calls completed ok
                        // errorFound |= !methods._checkAjaxStatus(options);

                        // third, check status and scroll the container accordingly
                        form.trigger("jqv.form.result", [errorFound]);

                        if (errorFound) {
                                if (options.scroll) {
                                        var destination=first_err.offset().top;
                                        var fixleft = first_err.offset().left;

                                        //prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10)
                                        var positionType=options.promptPosition;
                                        if (typeof(positionType)=='string' && positionType.indexOf(":")!=-1)
                                                positionType=positionType.substring(0,positionType.indexOf(":"));

                                        if (positionType!="bottomRight" && positionType!="bottomLeft") {
                                                var prompt_err= methods._getPrompt(first_err);
                                                if (prompt_err) {
                                                        destination=prompt_err.offset().top;
                                                }
                                        }
                                        
                                        // Offset the amount the page scrolls by an amount in px to accomodate fixed elements at top of page
                                        if (options.scrollOffset) {
                                                destination -= options.scrollOffset;
                                        }

                                        // get the position of the first error, there should be at least one, no need to check this
                                        //var destination = form.find(".formError:not('.greenPopup'):first").offset().top;
                                        if (options.isOverflown) {
                                                var overflowDIV = $(options.overflownDIV);
                                                if(!overflowDIV.length) return false;
                                                var scrollContainerScroll = overflowDIV.scrollTop();
                                                var scrollContainerPos = -parseInt(overflowDIV.offset().top);

                                                destination += scrollContainerScroll + scrollContainerPos - 5;
                                                var scrollContainer = $(options.overflownDIV + ":not(:animated)");

                                                scrollContainer.animate({ scrollTop: destination }, 1100, function(){
                                                        if(options.focusFirstField) first_err.focus();
                                                });

                                        } else {
                                                $("html, body").animate({
                                                        scrollTop: destination
                                                }, 1100, function(){
                                                        if(options.focusFirstField) first_err.focus();
                                                });
                                                $("html, body").animate({scrollLeft: fixleft},1100)
                                        }

                                } else if(options.focusFirstField)
                                        first_err.focus();
                                return false;
                        }
                        return true;
                },
                /**
                * This method is called to perform an ajax form validation.
                * During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true
                *
                * @param {jqObject} form
                * @param {Map} options
                */
                _validateFormWithAjax: function(form, options) {

                        var data = form.serialize();
                                                                        var type = (options.ajaxFormValidationMethod) ? options.ajaxFormValidationMethod : "GET";
                        var url = (options.ajaxFormValidationURL) ? options.ajaxFormValidationURL : form.attr("action");
                                                                        var dataType = (options.dataType) ? options.dataType : "json";
                        $.ajax({
                                type: type,
                                url: url,
                                cache: false,
                                dataType: dataType,
                                data: data,
                                form: form,
                                methods: methods,
                                options: options,
                                beforeSend: function() {
                                        return options.onBeforeAjaxFormValidation(form, options);
                                },
                                error: function(data, transport) {
                                        if (options.onFailure) {
                                                options.onFailure(data, transport);
                                        } else {
                                                methods._ajaxError(data, transport);
                                        }
                                },
                                success: function(json) {
                                        if ((dataType == "json") && (json !== true)) {
                                                // getting to this case doesn't necessary means that the form is invalid
                                                // the server may return green or closing prompt actions
                                                // this flag helps figuring it out
                                                var errorInForm=false;
                                                for (var i = 0; i < json.length; i++) {
                                                        var value = json[i];

                                                        var errorFieldId = value[0];
                                                        var errorField = $($("#" + errorFieldId)[0]);

                                                        // make sure we found the element
                                                        if (errorField.length == 1) {

                                                                // promptText or selector
                                                                var msg = value[2];
                                                                // if the field is valid
                                                                if (value[1] == true) {

                                                                        if (msg == ""  || !msg){
                                                                                // if for some reason, status==true and error="", just close the prompt
                                                                                methods._closePrompt(errorField);
                                                                        } else {
                                                                                // the field is valid, but we are displaying a green prompt
                                                                                if (options.allrules[msg]) {
                                                                                        var txt = options.allrules[msg].alertTextOk;
                                                                                        if (txt)
                                                                                                msg = txt;
                                                                                }
                                                                                if (options.showPrompts) methods._showPrompt(errorField, msg, "pass", false, options, true);
                                                                        }
                                                                } else {
                                                                        // the field is invalid, show the red error prompt
                                                                        errorInForm|=true;
                                                                        if (options.allrules[msg]) {
                                                                                var txt = options.allrules[msg].alertText;
                                                                                if (txt)
                                                                                        msg = txt;
                                                                        }
                                                                        if(options.showPrompts) methods._showPrompt(errorField, msg, "", false, options, true);
                                                                }
                                                        }
                                                }
                                                options.onAjaxFormComplete(!errorInForm, form, json, options);
                                        } else
                                                options.onAjaxFormComplete(true, form, json, options);

                                }
                        });

                },
                /**
                * Validates field, shows prompts accordingly
                *
                * @param {jqObject}
                *            field
                * @param {Array[String]}
                *            field's validation rules
                * @param {Map}
                *            user options
                * @return false if field is valid (It is inversed for *fields*, it return false on validate and true on errors.)
                */
                _validateField: function(field, options, skipAjaxValidation) {
                        if (!field.attr("id")) {
                                field.attr("id", "form-validation-field-" + $.validationEngine.fieldIdCounter);
                                ++$.validationEngine.fieldIdCounter;
                        }

           if (!options.validateNonVisibleFields && (field.is(":hidden") && !options.prettySelect || field.parent().is(":hidden")))
                                return false;

                        var rulesParsing = field.attr(options.validateAttribute);
                        var getRules = /validate\[(.*)\]/.exec(rulesParsing);

                        if (!getRules)
                                return false;
                        var str = getRules[1];
                        var rules = str.split(/\[|,|\]/);

                        // true if we ran the ajax validation, tells the logic to stop messing with prompts
                        var isAjaxValidator = false;
                        var fieldName = field.attr("name");
                        var promptText = "";
                        var promptType = "";
                        var required = false;
                        var limitErrors = false;
                        options.isError = false;
                        options.showArrow = true;
                        
                        // If the programmer wants to limit the amount of error messages per field,
                        if (options.maxErrorsPerField > 0) {
                                limitErrors = true;
                        }

                        var form = $(field.closest("form, .validationEngineContainer"));
                        // Fix for adding spaces in the rules
                        for (var i = 0; i < rules.length; i++) {
                                rules[i] = rules[i].replace(" ", "");
                                // Remove any parsing errors
                                if (rules[i] === '') {
                                        delete rules[i];
                                }
                        }

                        for (var i = 0, field_errors = 0; i < rules.length; i++) {
                                
                                // If we are limiting errors, and have hit the max, break
                                if (limitErrors && field_errors >= options.maxErrorsPerField) {
                                        // If we haven't hit a required yet, check to see if there is one in the validation rules for this
                                        // field and that it's index is greater or equal to our current index
                                        if (!required) {
                                                var have_required = $.inArray('required', rules);
                                                required = (have_required != -1 &&  have_required >= i);
                                        }
                                        break;
                                }
                                
                                
                                var errorMsg = undefined;
                                switch (rules[i]) {

                                        case "required":
                                                required = true;
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._required);
                                                break;
                                        case "custom":
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._custom);
                                                break;
                                        case "groupRequired":
                                                // Check is its the first of group, if not, reload validation with first field
                                                // AND continue normal validation on present field
                                                var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]";
                                                var firstOfGroup = form.find(classGroup).eq(0);
                                                if(firstOfGroup[0] != field[0]){

                                                        methods._validateField(firstOfGroup, options, skipAjaxValidation); 
                                                        options.showArrow = true;

                                                }
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._groupRequired);
                                                if(errorMsg)  required = true;
                                                options.showArrow = false;
                                                break;
                                        case "ajax":
                                                // AJAX defaults to returning it's loading message
                                                errorMsg = methods._ajax(field, rules, i, options);
                                                if (errorMsg) {
                                                        promptType = "load";
                                                }
                                                break;
                                        case "minSize":
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minSize);
                                                break;
                                        case "maxSize":
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxSize);
                                                break;
                                        case "min":
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._min);
                                                break;
                                        case "max":
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._max);
                                                break;
                                        case "past":
                                                errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._past);
                                                break;
                                        case "future":
                                                errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._future);
                                                break;
                                        case "dateRange":
                                                var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]";
                                                options.firstOfGroup = form.find(classGroup).eq(0);
                                                options.secondOfGroup = form.find(classGroup).eq(1);

                                                //if one entry out of the pair has value then proceed to run through validation
                                                if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) {
                                                        errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateRange);
                                                }
                                                if (errorMsg) required = true;
                                                options.showArrow = false;
                                                break;

                                        case "dateTimeRange":
                                                var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]";
                                                options.firstOfGroup = form.find(classGroup).eq(0);
                                                options.secondOfGroup = form.find(classGroup).eq(1);

                                                //if one entry out of the pair has value then proceed to run through validation
                                                if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) {
                                                        errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateTimeRange);
                                                }
                                                if (errorMsg) required = true;
                                                options.showArrow = false;
                                                break;
                                        case "maxCheckbox":
                                                field = $(form.find("input[name='" + fieldName + "']"));
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxCheckbox);
                                                break;
                                        case "minCheckbox":
                                                field = $(form.find("input[name='" + fieldName + "']"));
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minCheckbox);
                                                break;
                                        case "equals":
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._equals);
                                                break;
                                        case "funcCall":
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._funcCall);
                                                break;
                                        case "creditCard":
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._creditCard);
                                                break;
                                        case "condRequired":
                                                errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._condRequired);
                                                if (errorMsg !== undefined) {
                                                        required = true;
                                                }
                                                break;

                                        default:
                                }
                                
                                var end_validation = false;
                                
                                // If we were passed back an message object, check what the status was to determine what to do
                                if (typeof errorMsg == "object") {
                                        switch (errorMsg.status) {
                                                case "_break":
                                                        end_validation = true;
                                                        break;
                                                // If we have an error message, set errorMsg to the error message
                                                case "_error":
                                                        errorMsg = errorMsg.message;
                                                        break;
                                                // If we want to throw an error, but not show a prompt, return early with true
                                                case "_error_no_prompt":
                                                        return true;
                                                        break;
                                                // Anything else we continue on
                                                default:
                                                        break;
                                        }
                                }
                                
                                // If it has been specified that validation should end now, break
                                if (end_validation) {
                                        break;
                                }
                                
                                // If we have a string, that means that we have an error, so add it to the error message.
                                if (typeof errorMsg == 'string') {
                                        promptText += errorMsg + "<br/>";
                                        options.isError = true;
                                        field_errors++;
                                }       
                        }
                        // If the rules required is not added, an empty field is not validated
                        //the 3rd condition is added so that even empty password fields should be equal
                        //otherwise if one is filled and another left empty, the "equal" condition would fail
                        //which does not make any sense
                        if(!required && !(field.val()) && field.val().length < 1 && rules.indexOf("equals") < 0) options.isError = false;

                        // Hack for radio/checkbox group button, the validation go into the
                        // first radio/checkbox of the group
                        var fieldType = field.prop("type");
                        var positionType=field.data("promptPosition") || options.promptPosition;

                        if ((fieldType == "radio" || fieldType == "checkbox") && form.find("input[name='" + fieldName + "']").size() > 1) {
                                if(positionType === 'inline') {
                                        field = $(form.find("input[name='" + fieldName + "'][type!=hidden]:last"));
                                } else {
                                field = $(form.find("input[name='" + fieldName + "'][type!=hidden]:first"));
                                }
                                options.showArrow = false;
                        }

                        if(field.is(":hidden") && options.prettySelect) {
                                field = form.find("#" + options.usePrefix + methods._jqSelector(field.attr('id')) + options.useSuffix);
                        }

                        if (options.isError && options.showPrompts){
                                methods._showPrompt(field, promptText, promptType, false, options);
                        }else{
                                if (!isAjaxValidator) methods._closePrompt(field);
                        }

                        if (!isAjaxValidator) {
                                field.trigger("jqv.field.result", [field, options.isError, promptText]);
                        }

                        /* Record error */
                        var errindex = $.inArray(field[0], options.InvalidFields);
                        if (errindex == -1) {
                                if (options.isError)
                                options.InvalidFields.push(field[0]);
                        } else if (!options.isError) {
                                options.InvalidFields.splice(errindex, 1);
                        }
                                
                        methods._handleStatusCssClasses(field, options);
        
                        /* run callback function for each field */
                        if (options.isError && options.onFieldFailure)
                                options.onFieldFailure(field);

                        if (!options.isError && options.onFieldSuccess)
                                options.onFieldSuccess(field);

                        return options.isError;
                },
                /**
                * Handling css classes of fields indicating result of validation 
                *
                * @param {jqObject}
                *            field
                * @param {Array[String]}
                *            field's validation rules            
                * @private
                */
                _handleStatusCssClasses: function(field, options) {
                        /* remove all classes */
                        if(options.addSuccessCssClassToField)
                                field.removeClass(options.addSuccessCssClassToField);
                        
                        if(options.addFailureCssClassToField)
                                field.removeClass(options.addFailureCssClassToField);
                        
                        /* Add classes */
                        if (options.addSuccessCssClassToField && !options.isError)
                                field.addClass(options.addSuccessCssClassToField);
                        
                        if (options.addFailureCssClassToField && options.isError)
                                field.addClass(options.addFailureCssClassToField);              
                },
                
                 /********************
                  * _getErrorMessage
                  *
                  * @param form
                  * @param field
                  * @param rule
                  * @param rules
                  * @param i
                  * @param options
                  * @param originalValidationMethod
                  * @return {*}
                  * @private
                  */
                 _getErrorMessage:function (form, field, rule, rules, i, options, originalValidationMethod) {
                         // If we are using the custon validation type, build the index for the rule.
                         // Otherwise if we are doing a function call, make the call and return the object
                         // that is passed back.
                         var rule_index = jQuery.inArray(rule, rules);
                         if (rule === "custom" || rule === "funcCall") {
                                 var custom_validation_type = rules[rule_index + 1];
                                 rule = rule + "[" + custom_validation_type + "]";
                                 // Delete the rule from the rules array so that it doesn't try to call the
                            // same rule over again
                            delete(rules[rule_index]);
                         }
                         // Change the rule to the composite rule, if it was different from the original
                         var alteredRule = rule;


                         var element_classes = (field.attr("data-validation-engine")) ? field.attr("data-validation-engine") : field.attr("class");
                         var element_classes_array = element_classes.split(" ");

                         // Call the original validation method. If we are dealing with dates or checkboxes, also pass the form
                         var errorMsg;
                         if (rule == "future" || rule == "past"  || rule == "maxCheckbox" || rule == "minCheckbox") {
                                 errorMsg = originalValidationMethod(form, field, rules, i, options);
                         } else {
                                 errorMsg = originalValidationMethod(field, rules, i, options);
                         }

                         // If the original validation method returned an error and we have a custom error message,
                         // return the custom message instead. Otherwise return the original error message.
                         if (errorMsg != undefined) {
                                 var custom_message = methods._getCustomErrorMessage($(field), element_classes_array, alteredRule, options);
                                 if (custom_message) errorMsg = custom_message;
                         }
                         return errorMsg;

                 },
                 _getCustomErrorMessage:function (field, classes, rule, options) {
                        var custom_message = false;
                        var validityProp = /^custom\[.*\]$/.test(rule) ? methods._validityProp["custom"] : methods._validityProp[rule];
                         // If there is a validityProp for this rule, check to see if the field has an attribute for it
                        if (validityProp != undefined) {
                                custom_message = field.attr("data-errormessage-"+validityProp);
                                // If there was an error message for it, return the message
                                if (custom_message != undefined) 
                                        return custom_message;
                        }
                        custom_message = field.attr("data-errormessage");
                         // If there is an inline custom error message, return it
                        if (custom_message != undefined) 
                                return custom_message;
                        var id = '#' + field.attr("id");
                        // If we have custom messages for the element's id, get the message for the rule from the id.
                        // Otherwise, if we have custom messages for the element's classes, use the first class message we find instead.
                        if (typeof options.custom_error_messages[id] != "undefined" &&
                                typeof options.custom_error_messages[id][rule] != "undefined" ) {
                                                  custom_message = options.custom_error_messages[id][rule]['message'];
                        } else if (classes.length > 0) {
                                for (var i = 0; i < classes.length && classes.length > 0; i++) {
                                         var element_class = "." + classes[i];
                                        if (typeof options.custom_error_messages[element_class] != "undefined" &&
                                                typeof options.custom_error_messages[element_class][rule] != "undefined") {
                                                        custom_message = options.custom_error_messages[element_class][rule]['message'];
                                                        break;
                                        }
                                }
                        }
                        if (!custom_message &&
                                typeof options.custom_error_messages[rule] != "undefined" &&
                                typeof options.custom_error_messages[rule]['message'] != "undefined"){
                                         custom_message = options.custom_error_messages[rule]['message'];
                         }
                         return custom_message;
                 },
                 _validityProp: {
                         "required": "value-missing",
                         "custom": "custom-error",
                         "groupRequired": "value-missing",
                         "ajax": "custom-error",
                         "minSize": "range-underflow",
                         "maxSize": "range-overflow",
                         "min": "range-underflow",
                         "max": "range-overflow",
                         "past": "type-mismatch",
                         "future": "type-mismatch",
                         "dateRange": "type-mismatch",
                         "dateTimeRange": "type-mismatch",
                         "maxCheckbox": "range-overflow",
                         "minCheckbox": "range-underflow",
                         "equals": "pattern-mismatch",
                         "funcCall": "custom-error",
                         "creditCard": "pattern-mismatch",
                         "condRequired": "value-missing"
                 },
                /**
                * Required validation
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @param {bool} condRequired flag when method is used for internal purpose in condRequired check
                * @return an error string if validation failed
                */
                _required: function(field, rules, i, options, condRequired) {
                        switch (field.prop("type")) {
                                case "text":
                                case "password":
                                case "textarea":
                                case "file":
                                case "select-one":
                                case "select-multiple":
                                default:
                                        var field_val      = $.trim( field.val()                               );
                                        var dv_placeholder = $.trim( field.attr("data-validation-placeholder") );
                                        var placeholder    = $.trim( field.attr("placeholder")                 );
                                        if (
                                                   ( !field_val                                    )
                                                || ( dv_placeholder && field_val == dv_placeholder )
                                                || ( placeholder    && field_val == placeholder    )
                                        ) {
                                                return options.allrules[rules[i]].alertText;
                                        }
                                        break;
                                case "radio":
                                case "checkbox":
                                        // new validation style to only check dependent field
                                        if (condRequired) {
                                                if (!field.attr('checked')) {
                                                        return options.allrules[rules[i]].alertTextCheckboxMultiple;
                                                }
                                                break;
                                        }
                                        // old validation style
                                        var form = field.closest("form, .validationEngineContainer");
                                        var name = field.attr("name");
                                        if (form.find("input[name='" + name + "']:checked").size() == 0) {
                                                if (form.find("input[name='" + name + "']:visible").size() == 1)
                                                        return options.allrules[rules[i]].alertTextCheckboxe;
                                                else
                                                        return options.allrules[rules[i]].alertTextCheckboxMultiple;
                                        }
                                        break;
                        }
                },
                /**
                * Validate that 1 from the group field is required
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _groupRequired: function(field, rules, i, options) {
                        var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]";
                        var isValid = false;
                        // Check all fields from the group
                        field.closest("form, .validationEngineContainer").find(classGroup).each(function(){
                                if(!methods._required($(this), rules, i, options)){
                                        isValid = true;
                                        return false;
                                }
                        }); 

                        if(!isValid) {
                  return options.allrules[rules[i]].alertText;
                }
                },
                /**
                * Validate rules
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _custom: function(field, rules, i, options) {
                        var customRule = rules[i + 1];
                        var rule = options.allrules[customRule];
                        var fn;
                        if(!rule) {
                                alert("jqv:custom rule not found - "+customRule);
                                return;
                        }
                        
                        if(rule["regex"]) {
                                 var ex=rule.regex;
                                        if(!ex) {
                                                alert("jqv:custom regex not found - "+customRule);
                                                return;
                                        }
                                        var pattern = new RegExp(ex);

                                        if (!pattern.test(field.val())) return options.allrules[customRule].alertText;
                                        
                        } else if(rule["func"]) {
                                fn = rule["func"]; 
                                 
                                if (typeof(fn) !== "function") {
                                        alert("jqv:custom parameter 'function' is no function - "+customRule);
                                                return;
                                }
                                 
                                if (!fn(field, rules, i, options))
                                        return options.allrules[customRule].alertText;
                        } else {
                                alert("jqv:custom type not allowed "+customRule);
                                        return;
                        }
                },
                /**
                * Validate custom function outside of the engine scope
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _funcCall: function(field, rules, i, options) {
                        var functionName = rules[i + 1];
                        var fn;
                        if(functionName.indexOf('.') >-1)
                        {
                                var namespaces = functionName.split('.');
                                var scope = window;
                                while(namespaces.length)
                                {
                                        scope = scope[namespaces.shift()];
                                }
                                fn = scope;
                        }
                        else
                                fn = window[functionName] || options.customFunctions[functionName];
                        if (typeof(fn) == 'function')
                                return fn(field, rules, i, options);

                },
                /**
                * Field match
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _equals: function(field, rules, i, options) {
                        var equalsField = rules[i + 1];

                        if (field.val() != $("#" + equalsField).val())
                                return options.allrules.equals.alertText;
                },
                /**
                * Check the maximum size (in characters)
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _maxSize: function(field, rules, i, options) {
                        var max = rules[i + 1];
                        var len = field.val().length;

                        if (len > max) {
                                var rule = options.allrules.maxSize;
                                return rule.alertText + max + rule.alertText2;
                        }
                },
                /**
                * Check the minimum size (in characters)
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _minSize: function(field, rules, i, options) {
                        var min = rules[i + 1];
                        var len = field.val().length;

                        if (len < min) {
                                var rule = options.allrules.minSize;
                                return rule.alertText + min + rule.alertText2;
                        }
                },
                /**
                * Check number minimum value
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _min: function(field, rules, i, options) {
                        var min = parseFloat(rules[i + 1]);
                        var len = parseFloat(field.val());

                        if (len < min) {
                                var rule = options.allrules.min;
                                if (rule.alertText2) return rule.alertText + min + rule.alertText2;
                                return rule.alertText + min;
                        }
                },
                /**
                * Check number maximum value
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _max: function(field, rules, i, options) {
                        var max = parseFloat(rules[i + 1]);
                        var len = parseFloat(field.val());

                        if (len >max ) {
                                var rule = options.allrules.max;
                                if (rule.alertText2) return rule.alertText + max + rule.alertText2;
                                //orefalo: to review, also do the translations
                                return rule.alertText + max;
                        }
                },
                /**
                * Checks date is in the past
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _past: function(form, field, rules, i, options) {

                        var p=rules[i + 1];
                        var fieldAlt = $(form.find("*[name='" + p.replace(/^#+/, '') + "']"));
                        var pdate;

                        if (p.toLowerCase() == "now") {
                                pdate = new Date();
                        } else if (undefined != fieldAlt.val()) {
                                if (fieldAlt.is(":disabled"))
                                        return;
                                pdate = methods._parseDate(fieldAlt.val());
                        } else {
                                pdate = methods._parseDate(p);
                        }
                        var vdate = methods._parseDate(field.val());

                        if (vdate > pdate ) {
                                var rule = options.allrules.past;
                                if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
                                return rule.alertText + methods._dateToString(pdate);
                        }
                },
                /**
                * Checks date is in the future
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _future: function(form, field, rules, i, options) {

                        var p=rules[i + 1];
                        var fieldAlt = $(form.find("*[name='" + p.replace(/^#+/, '') + "']"));
                        var pdate;

                        if (p.toLowerCase() == "now") {
                                pdate = new Date();
                        } else if (undefined != fieldAlt.val()) {
                                if (fieldAlt.is(":disabled"))
                                        return;
                                pdate = methods._parseDate(fieldAlt.val());
                        } else {
                                pdate = methods._parseDate(p);
                        }
                        var vdate = methods._parseDate(field.val());

                        if (vdate < pdate ) {
                                var rule = options.allrules.future;
                                if (rule.alertText2)
                                        return rule.alertText + methods._dateToString(pdate) + rule.alertText2;
                                return rule.alertText + methods._dateToString(pdate);
                        }
                },
                /**
                * Checks if valid date
                *
                * @param {string} date string
                * @return a bool based on determination of valid date
                */
                _isDate: function (value) {
                        var dateRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(?:(?:0?[1-9]|1[0-2])(\/|-)(?:0?[1-9]|1\d|2[0-8]))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(0?2(\/|-)29)(\/|-)(?:(?:0[48]00|[13579][26]00|[2468][048]00)|(?:\d\d)?(?:0[48]|[2468][048]|[13579][26]))$/);
                        return dateRegEx.test(value);
                },
                /**
                * Checks if valid date time
                *
                * @param {string} date string
                * @return a bool based on determination of valid date time
                */
                _isDateTime: function (value){
                        var dateTimeRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1}$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^((1[012]|0?[1-9]){1}\/(0?[1-9]|[12][0-9]|3[01]){1}\/\d{2,4}\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1})$/);
                        return dateTimeRegEx.test(value);
                },
                //Checks if the start date is before the end date
                //returns true if end is later than start
                _dateCompare: function (start, end) {
                        return (new Date(start.toString()) < new Date(end.toString()));
                },
                /**
                * Checks date range
                *
                * @param {jqObject} first field name
                * @param {jqObject} second field name
                * @return an error string if validation failed
                */
                _dateRange: function (field, rules, i, options) {
                        //are not both populated
                        if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) {
                                return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
                        }

                        //are not both dates
                        if (!methods._isDate(options.firstOfGroup[0].value) || !methods._isDate(options.secondOfGroup[0].value)) {
                                return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
                        }

                        //are both dates but range is off
                        if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) {
                                return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
                        }
                },
                /**
                * Checks date time range
                *
                * @param {jqObject} first field name
                * @param {jqObject} second field name
                * @return an error string if validation failed
                */
                _dateTimeRange: function (field, rules, i, options) {
                        //are not both populated
                        if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) {
                                return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
                        }
                        //are not both dates
                        if (!methods._isDateTime(options.firstOfGroup[0].value) || !methods._isDateTime(options.secondOfGroup[0].value)) {
                                return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
                        }
                        //are both dates but range is off
                        if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) {
                                return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2;
                        }
                },
                /**
                * Max number of checkbox selected
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _maxCheckbox: function(form, field, rules, i, options) {

                        var nbCheck = rules[i + 1];
                        var groupname = field.attr("name");
                        var groupSize = form.find("input[name='" + groupname + "']:checked").size();
                        if (groupSize > nbCheck) {
                                options.showArrow = false;
                                if (options.allrules.maxCheckbox.alertText2)
                                         return options.allrules.maxCheckbox.alertText + " " + nbCheck + " " + options.allrules.maxCheckbox.alertText2;
                                return options.allrules.maxCheckbox.alertText;
                        }
                },
                /**
                * Min number of checkbox selected
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _minCheckbox: function(form, field, rules, i, options) {

                        var nbCheck = rules[i + 1];
                        var groupname = field.attr("name");
                        var groupSize = form.find("input[name='" + groupname + "']:checked").size();
                        if (groupSize < nbCheck) {
                                options.showArrow = false;
                                return options.allrules.minCheckbox.alertText + " " + nbCheck + " " + options.allrules.minCheckbox.alertText2;
                        }
                },
                /**
                * Checks that it is a valid credit card number according to the
                * Luhn checksum algorithm.
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return an error string if validation failed
                */
                _creditCard: function(field, rules, i, options) {
                        //spaces and dashes may be valid characters, but must be stripped to calculate the checksum.
                        var valid = false, cardNumber = field.val().replace(/ +/g, '').replace(/-+/g, '');

                        var numDigits = cardNumber.length;
                        if (numDigits >= 14 && numDigits <= 16 && parseInt(cardNumber) > 0) {

                                var sum = 0, i = numDigits - 1, pos = 1, digit, luhn = new String();
                                do {
                                        digit = parseInt(cardNumber.charAt(i));
                                        luhn += (pos++ % 2 == 0) ? digit * 2 : digit;
                                } while (--i >= 0)

                                for (i = 0; i < luhn.length; i++) {
                                        sum += parseInt(luhn.charAt(i));
                                }
                                valid = sum % 10 == 0;
                        }
                        if (!valid) return options.allrules.creditCard.alertText;
                },
                /**
                * Ajax field validation
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                *            user options
                * @return nothing! the ajax validator handles the prompts itself
                */
                 _ajax: function(field, rules, i, options) {

                         var errorSelector = rules[i + 1];
                         var rule = options.allrules[errorSelector];
                         var extraData = rule.extraData;
                         var extraDataDynamic = rule.extraDataDynamic;
                         var data = {
                                "fieldId" : field.attr("id"),
                                "fieldValue" : field.val()
                         };

                         if (typeof extraData === "object") {
                                $.extend(data, extraData);
                         } else if (typeof extraData === "string") {
                                var tempData = extraData.split("&");
                                for(var i = 0; i < tempData.length; i++) {
                                        var values = tempData[i].split("=");
                                        if (values[0] && values[0]) {
                                                data[values[0]] = values[1];
                                        }
                                }
                         }

                         if (extraDataDynamic) {
                                 var tmpData = [];
                                 var domIds = String(extraDataDynamic).split(",");
                                 for (var i = 0; i < domIds.length; i++) {
                                         var id = domIds[i];
                                         if ($(id).length) {
                                                 var inputValue = field.closest("form, .validationEngineContainer").find(id).val();
                                                 var keyValue = id.replace('#', '') + '=' + escape(inputValue);
                                                 data[id.replace('#', '')] = inputValue;
                                         }
                                 }
                         }
                         
                         // If a field change event triggered this we want to clear the cache for this ID
                         if (options.eventTrigger == "field") {
                                delete(options.ajaxValidCache[field.attr("id")]);
                         }

                         // If there is an error or if the the field is already validated, do not re-execute AJAX
                         if (!options.isError && !methods._checkAjaxFieldStatus(field.attr("id"), options)) {
                                 $.ajax({
                                         type: options.ajaxFormValidationMethod,
                                         url: rule.url,
                                         cache: false,
                                         dataType: "json",
                                         data: data,
                                         field: field,
                                         rule: rule,
                                         methods: methods,
                                         options: options,
                                         beforeSend: function() {},
                                         error: function(data, transport) {
                                                if (options.onFailure) {
                                                        options.onFailure(data, transport);
                                                } else {
                                                        methods._ajaxError(data, transport);
                                                }
                                         },
                                         success: function(json) {

                                                 // asynchronously called on success, data is the json answer from the server
                                                 var errorFieldId = json[0];
                                                 //var errorField = $($("#" + errorFieldId)[0]);
                                                 var errorField = $("#"+ errorFieldId).eq(0);

                                                 // make sure we found the element
                                                 if (errorField.length == 1) {
                                                         var status = json[1];
                                                         // read the optional msg from the server
                                                         var msg = json[2];
                                                         if (!status) {
                                                                 // Houston we got a problem - display an red prompt
                                                                 options.ajaxValidCache[errorFieldId] = false;
                                                                 options.isError = true;

                                                                 // resolve the msg prompt
                                                                 if(msg) {
                                                                         if (options.allrules[msg]) {
                                                                                 var txt = options.allrules[msg].alertText;
                                                                                 if (txt) {
                                                                                        msg = txt;
                                                        }
                                                                         }
                                                                 }
                                                                 else
                                                                        msg = rule.alertText;

                                                                 if (options.showPrompts) methods._showPrompt(errorField, msg, "", true, options);
                                                         } else {
                                                                 options.ajaxValidCache[errorFieldId] = true;

                                                                 // resolves the msg prompt
                                                                 if(msg) {
                                                                         if (options.allrules[msg]) {
                                                                                 var txt = options.allrules[msg].alertTextOk;
                                                                                 if (txt) {
                                                                                        msg = txt;
                                                        }
                                                                         }
                                                                 }
                                                                 else
                                                                 msg = rule.alertTextOk;

                                                                 if (options.showPrompts) {
                                                                         // see if we should display a green prompt
                                                                         if (msg)
                                                                                methods._showPrompt(errorField, msg, "pass", true, options);
                                                                         else
                                                                                methods._closePrompt(errorField);
                                                                }
                                                                
                                                                 // If a submit form triggered this, we want to re-submit the form
                                                                 if (options.eventTrigger == "submit")
                                                                        field.closest("form").submit();
                                                         }
                                                 }
                                                 errorField.trigger("jqv.field.result", [errorField, options.isError, msg]);
                                         }
                                 });
                                 
                                 return rule.alertTextLoad;
                         }
                 },
                /**
                * Common method to handle ajax errors
                *
                * @param {Object} data
                * @param {Object} transport
                */
                _ajaxError: function(data, transport) {
                        if(data.status == 0 && transport == null)
                                alert("The page is not served from a server! ajax call failed");
                        else if(typeof console != "undefined")
                                console.log("Ajax error: " + data.status + " " + transport);
                },
                /**
                * date -> string
                *
                * @param {Object} date
                */
                _dateToString: function(date) {
                        return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate();
                },
                /**
                * Parses an ISO date
                * @param {String} d
                */
                _parseDate: function(d) {

                        var dateParts = d.split("-");
                        if(dateParts==d)
                                dateParts = d.split("/");
                        if(dateParts==d) {
                                dateParts = d.split(".");
                                return new Date(dateParts[2], (dateParts[1] - 1), dateParts[0]);
                        }
                        return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]);
                },
                /**
                * Builds or updates a prompt with the given information
                *
                * @param {jqObject} field
                * @param {String} promptText html text to display type
                * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
                * @param {boolean} ajaxed - use to mark fields than being validated with ajax
                * @param {Map} options user options
                */
                 _showPrompt: function(field, promptText, type, ajaxed, options, ajaxform) {
                        //Check if we need to adjust what element to show the prompt on
                        if(field.data('jqv-prompt-at') instanceof jQuery ){
                                field = field.data('jqv-prompt-at');
                        } else if(field.data('jqv-prompt-at')) {
                                field = $(field.data('jqv-prompt-at'));
                        }

                         var prompt = methods._getPrompt(field);
                         // The ajax submit errors are not see has an error in the form,
                         // When the form errors are returned, the engine see 2 bubbles, but those are ebing closed by the engine at the same time
                         // Because no error was found befor submitting
                         if(ajaxform) prompt = false;
                         // Check that there is indded text
                         if($.trim(promptText)){ 
                                 if (prompt)
                                        methods._updatePrompt(field, prompt, promptText, type, ajaxed, options);
                                 else
                                        methods._buildPrompt(field, promptText, type, ajaxed, options);
                        }
                 },
                /**
                * Builds and shades a prompt for the given field.
                *
                * @param {jqObject} field
                * @param {String} promptText html text to display type
                * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
                * @param {boolean} ajaxed - use to mark fields than being validated with ajax
                * @param {Map} options user options
                */
                _buildPrompt: function(field, promptText, type, ajaxed, options) {

                        // create the prompt
                        var prompt = $('<div>');
                        prompt.addClass(methods._getClassName(field.attr("id")) + "formError");
                        // add a class name to identify the parent form of the prompt
                        prompt.addClass("parentForm"+methods._getClassName(field.closest('form, .validationEngineContainer').attr("id")));
                        prompt.addClass("formError");

                        switch (type) {
                                case "pass":
                                        prompt.addClass("greenPopup");
                                        break;
                                case "load":
                                        prompt.addClass("blackPopup");
                                        break;
                                default:
                                        /* it has error  */
                                        //alert("unknown popup type:"+type);
                        }
                        if (ajaxed)
                                prompt.addClass("ajaxed");

                        // create the prompt content
                        var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt);

                        // determine position type
                        var positionType=field.data("promptPosition") || options.promptPosition;

                        // create the css arrow pointing at the field
                        // note that there is no triangle on max-checkbox and radio
                        if (options.showArrow) {
                                var arrow = $('<div>').addClass("formErrorArrow");

                                //prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10)
                                if (typeof(positionType)=='string') 
                                {
                                        var pos=positionType.indexOf(":");
                                        if(pos!=-1)
                                                positionType=positionType.substring(0,pos);
                                }

                                switch (positionType) {
                                        case "bottomLeft":
                                        case "bottomRight":
                                                prompt.find(".formErrorContent").before(arrow);
                                                arrow.addClass("formErrorArrowBottom").html('<div class="line1"><!-- --></div><div class="line2"><!-- --></div><div class="line3"><!-- --></div><div class="line4"><!-- --></div><div class="line5"><!-- --></div><div class="line6"><!-- --></div><div class="line7"><!-- --></div><div class="line8"><!-- --></div><div class="line9"><!-- --></div><div class="line10"><!-- --></div>');
                                                break;
                                        case "topLeft":
                                        case "topRight":
                                                arrow.html('<div class="line10"><!-- --></div><div class="line9"><!-- --></div><div class="line8"><!-- --></div><div class="line7"><!-- --></div><div class="line6"><!-- --></div><div class="line5"><!-- --></div><div class="line4"><!-- --></div><div class="line3"><!-- --></div><div class="line2"><!-- --></div><div class="line1"><!-- --></div>');
                                                prompt.append(arrow);
                                                break;
                                }
                        }
                        // Add custom prompt class
                        if (options.addPromptClass)
                                prompt.addClass(options.addPromptClass);

            // Add custom prompt class defined in element
            var requiredOverride = field.attr('data-required-class');
            if(requiredOverride !== undefined) {
                prompt.addClass(requiredOverride);
            } else {
                if(options.prettySelect) {
                    if($('#' + field.attr('id')).next().is('select')) {
                        var prettyOverrideClass = $('#' + field.attr('id').substr(options.usePrefix.length).substring(options.useSuffix.length)).attr('data-required-class');
                        if(prettyOverrideClass !== undefined) {
                            prompt.addClass(prettyOverrideClass);
                        }
                    }
                }
            }

                        prompt.css({
                                "opacity": 0
                        });
                        if(positionType === 'inline') {
                                prompt.addClass("inline");
                                if(typeof field.attr('data-prompt-target') !== 'undefined' && $('#'+field.attr('data-prompt-target')).length > 0) {
                                        prompt.appendTo($('#'+field.attr('data-prompt-target')));
                                } else {
                                        field.after(prompt);
                                }
                        } else {
                                field.before(prompt);                           
                        }
                        
                        var pos = methods._calculatePosition(field, prompt, options);
                        prompt.css({
                                'position': positionType === 'inline' ? 'relative' : 'absolute',
                                "top": pos.callerTopPosition,
                                "left": pos.callerleftPosition,
                                "marginTop": pos.marginTopSize,
                                "opacity": 0
                        }).data("callerField", field);
                        

                        if (options.autoHidePrompt) {
                                setTimeout(function(){
                                        prompt.animate({
                                                "opacity": 0
                                        },function(){
                                                prompt.closest('.formErrorOuter').remove();
                                                prompt.remove();
                                        });
                                }, options.autoHideDelay);
                        } 
                        return prompt.animate({
                                "opacity": 0.87
                        });
                },
                /**
                * Updates the prompt text field - the field for which the prompt
                * @param {jqObject} field
                * @param {String} promptText html text to display type
                * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red)
                * @param {boolean} ajaxed - use to mark fields than being validated with ajax
                * @param {Map} options user options
                */
                _updatePrompt: function(field, prompt, promptText, type, ajaxed, options, noAnimation) {

                        if (prompt) {
                                if (typeof type !== "undefined") {
                                        if (type == "pass")
                                                prompt.addClass("greenPopup");
                                        else
                                                prompt.removeClass("greenPopup");

                                        if (type == "load")
                                                prompt.addClass("blackPopup");
                                        else
                                                prompt.removeClass("blackPopup");
                                }
                                if (ajaxed)
                                        prompt.addClass("ajaxed");
                                else
                                        prompt.removeClass("ajaxed");

                                prompt.find(".formErrorContent").html(promptText);

                                var pos = methods._calculatePosition(field, prompt, options);
                                var css = {"top": pos.callerTopPosition,
                                "left": pos.callerleftPosition,
                                "marginTop": pos.marginTopSize};

                                if (noAnimation)
                                        prompt.css(css);
                                else
                                        prompt.animate(css);
                        }
                },
                /**
                * Closes the prompt associated with the given field
                *
                * @param {jqObject}
                *            field
                */
                 _closePrompt: function(field) {
                         var prompt = methods._getPrompt(field);
                         if (prompt)
                                 prompt.fadeTo("fast", 0, function() {
                                         prompt.parent('.formErrorOuter').remove();
                                         prompt.remove();
                                 });
                 },
                 closePrompt: function(field) {
                         return methods._closePrompt(field);
                 },
                /**
                * Returns the error prompt matching the field if any
                *
                * @param {jqObject}
                *            field
                * @return undefined or the error prompt (jqObject)
                */
                _getPrompt: function(field) {
                                var formId = $(field).closest('form, .validationEngineContainer').attr('id');
                        var className = methods._getClassName(field.attr("id")) + "formError";
                                var match = $("." + methods._escapeExpression(className) + '.parentForm' + methods._getClassName(formId))[0];
                        if (match)
                        return $(match);
                },
                /**
                  * Returns the escapade classname
                  *
                  * @param {selector}
                  *            className
                  */
                  _escapeExpression: function (selector) {
                          return selector.replace(/([#;&,\.\+\*\~':"\!\^$\[\]\(\)=>\|])/g, "\\$1");
                  },
                /**
                 * returns true if we are in a RTLed document
                 *
                 * @param {jqObject} field
                 */
                isRTL: function(field)
                {
                        var $document = $(document);
                        var $body = $('body');
                        var rtl =
                                (field && field.hasClass('rtl')) ||
                                (field && (field.attr('dir') || '').toLowerCase()==='rtl') ||
                                $document.hasClass('rtl') ||
                                ($document.attr('dir') || '').toLowerCase()==='rtl' ||
                                $body.hasClass('rtl') ||
                                ($body.attr('dir') || '').toLowerCase()==='rtl';
                        return Boolean(rtl);
                },
                /**
                * Calculates prompt position
                *
                * @param {jqObject}
                *            field
                * @param {jqObject}
                *            the prompt
                * @param {Map}
                *            options
                * @return positions
                */
                _calculatePosition: function (field, promptElmt, options) {

                        var promptTopPosition, promptleftPosition, marginTopSize;
                        var fieldWidth  = field.width();
                        var fieldLeft   = field.position().left; 
                        var fieldTop    =  field.position().top;
                        var fieldHeight         =  field.height();      
                        var promptHeight = promptElmt.height();


                        // is the form contained in an overflown container?
                        promptTopPosition = promptleftPosition = 0;
                        // compensation for the arrow
                        marginTopSize = -promptHeight;
                

                        //prompt positioning adjustment support
                        //now you can adjust prompt position
                        //usage: positionType:Xshift,Yshift
                        //for example:
                        //   bottomLeft:+20 means bottomLeft position shifted by 20 pixels right horizontally
                        //   topRight:20, -15 means topRight position shifted by 20 pixels to right and 15 pixels to top
                        //You can use +pixels, - pixels. If no sign is provided than + is default.
                        var positionType=field.data("promptPosition") || options.promptPosition;
                        var shift1="";
                        var shift2="";
                        var shiftX=0;
                        var shiftY=0;
                        if (typeof(positionType)=='string') {
                                //do we have any position adjustments ?
                                if (positionType.indexOf(":")!=-1) {
                                        shift1=positionType.substring(positionType.indexOf(":")+1);
                                        positionType=positionType.substring(0,positionType.indexOf(":"));

                                        //if any advanced positioning will be needed (percents or something else) - parser should be added here
                                        //for now we use simple parseInt()

                                        //do we have second parameter?
                                        if (shift1.indexOf(",") !=-1) {
                                                shift2=shift1.substring(shift1.indexOf(",") +1);
                                                shift1=shift1.substring(0,shift1.indexOf(","));
                                                shiftY=parseInt(shift2);
                                                if (isNaN(shiftY)) shiftY=0;
                                        };

                                        shiftX=parseInt(shift1);
                                        if (isNaN(shift1)) shift1=0;

                                };
                        };

                        
                        switch (positionType) {
                                default:
                                case "topRight":
                                        promptleftPosition +=  fieldLeft + fieldWidth - 30;
                                        promptTopPosition +=  fieldTop;
                                        break;

                                case "topLeft":
                                        promptTopPosition +=  fieldTop;
                                        promptleftPosition += fieldLeft; 
                                        break;

                                case "centerRight":
                                        promptTopPosition = fieldTop+4;
                                        marginTopSize = 0;
                                        promptleftPosition= fieldLeft + field.outerWidth(true)+5;
                                        break;
                                case "centerLeft":
                                        promptleftPosition = fieldLeft - (promptElmt.width() + 2);
                                        promptTopPosition = fieldTop+4;
                                        marginTopSize = 0;
                                        
                                        break;

                                case "bottomLeft":
                                        promptTopPosition = fieldTop + field.height() + 5;
                                        marginTopSize = 0;
                                        promptleftPosition = fieldLeft;
                                        break;
                                case "bottomRight":
                                        promptleftPosition = fieldLeft + fieldWidth - 30;
                                        promptTopPosition =  fieldTop +  field.height() + 5;
                                        marginTopSize = 0;
                                        break;
                                case "inline":
                                        promptleftPosition = 0;
                                        promptTopPosition = 0;
                                        marginTopSize = 0;
                        };

                

                        //apply adjusments if any
                        promptleftPosition += shiftX;
                        promptTopPosition  += shiftY;

                        return {
                                "callerTopPosition": promptTopPosition + "px",
                                "callerleftPosition": promptleftPosition + "px",
                                "marginTopSize": marginTopSize + "px"
                        };
                },
                /**
                * Saves the user options and variables in the form.data
                *
                * @param {jqObject}
                *            form - the form where the user option should be saved
                * @param {Map}
                *            options - the user options
                * @return the user options (extended from the defaults)
                */
                 _saveOptions: function(form, options) {

                         // is there a language localisation ?
                         if ($.validationEngineLanguage)
                         var allRules = $.validationEngineLanguage.allRules;
                         else
                         $.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page");
                         // --- Internals DO NOT TOUCH or OVERLOAD ---
                         // validation rules and i18
                         $.validationEngine.defaults.allrules = allRules;

                         var userOptions = $.extend(true,{},$.validationEngine.defaults,options);

                         form.data('jqv', userOptions);
                         return userOptions;
                 },

                 /**
                 * Removes forbidden characters from class name
                 * @param {String} className
                 */
                 _getClassName: function(className) {
                         if(className)
                                 return className.replace(/:/g, "_").replace(/\./g, "_");
                                          },
                /**
                 * Escape special character for jQuery selector
                 * http://totaldev.com/content/escaping-characters-get-valid-jquery-id
                 * @param {String} selector
                 */
                 _jqSelector: function(str){
                        return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
                },
                /**
                * Conditionally required field
                *
                * @param {jqObject} field
                * @param {Array[String]} rules
                * @param {int} i rules index
                * @param {Map}
                * user options
                * @return an error string if validation failed
                */
                _condRequired: function(field, rules, i, options) {
                        var idx, dependingField;

                        for(idx = (i + 1); idx < rules.length; idx++) {
                                dependingField = jQuery("#" + rules[idx]).first();

                                /* Use _required for determining wether dependingField has a value.
                                 * There is logic there for handling all field types, and default value; so we won't replicate that here
                                 * Indicate this special use by setting the last parameter to true so we only validate the dependingField on chackboxes and radio buttons (#462)
                                 */
                                if (dependingField.length && methods._required(dependingField, ["required"], 0, options, true) == undefined) {
                                        /* We now know any of the depending fields has a value,
                                         * so we can validate this field as per normal required code
                                         */
                                        return methods._required(field, ["required"], 0, options);
                                }
                        }
                },

            _submitButtonClick: function(event) {
                var button = $(this);
                var form = button.closest('form, .validationEngineContainer');
                form.data("jqv_submitButton", button.attr("id"));
            }
                  };

         /**
         * Plugin entry point.
         * You may pass an action as a parameter or a list of options.
         * if none, the init and attach methods are being called.
         * Remember: if you pass options, the attached method is NOT called automatically
         *
         * @param {String}
         *            method (optional) action
         */
         $.fn.validationEngine = function(method) {

                 var form = $(this);
                 if(!form[0]) return form;  // stop here if the form does not exist

                 if (typeof(method) == 'string' && method.charAt(0) != '_' && methods[method]) {

                         // make sure init is called once
                         if(method != "showPrompt" && method != "hide" && method != "hideAll")
                         methods.init.apply(form);

                         return methods[method].apply(form, Array.prototype.slice.call(arguments, 1));
                 } else if (typeof method == 'object' || !method) {

                         // default constructor with or without arguments
                         methods.init.apply(form, arguments);
                         return methods.attach.apply(form);
                 } else {
                         $.error('Method ' + method + ' does not exist in jQuery.validationEngine');
                 }
        };



        // LEAK GLOBAL OPTIONS
        $.validationEngine= {fieldIdCounter: 0,defaults:{

                // Name of the event triggering field validation
                validationEventTrigger: "blur",
                // Automatically scroll viewport to the first error
                scroll: true,
                // Focus on the first input
                focusFirstField:true,
                // Show prompts, set to false to disable prompts
                showPrompts: true,
       // Should we attempt to validate non-visible input fields contained in the form? (Useful in cases of tabbed containers, e.g. jQuery-UI tabs)
       validateNonVisibleFields: false,
                // Opening box position, possible locations are: topLeft,
                // topRight, bottomLeft, centerRight, bottomRight, inline
                // inline gets inserted after the validated field or into an element specified in data-prompt-target
                promptPosition: "topRight",
                bindMethod:"bind",
                // internal, automatically set to true when it parse a _ajax rule
                inlineAjax: false,
                // if set to true, the form data is sent asynchronously via ajax to the form.action url (get)
                ajaxFormValidation: false,
                // The url to send the submit ajax validation (default to action)
                ajaxFormValidationURL: false,
                // HTTP method used for ajax validation
                ajaxFormValidationMethod: 'get',
                // Ajax form validation callback method: boolean onComplete(form, status, errors, options)
                // retuns false if the form.submit event needs to be canceled.
                onAjaxFormComplete: $.noop,
                // called right before the ajax call, may return false to cancel
                onBeforeAjaxFormValidation: $.noop,
                // Stops form from submitting and execute function assiciated with it
                onValidationComplete: false,

                // Used when you have a form fields too close and the errors messages are on top of other disturbing viewing messages
                doNotShowAllErrosOnSubmit: false,
                // Object where you store custom messages to override the default error messages
                custom_error_messages:{},
                // true if you want to vind the input fields
                binded: true,
                // set to true, when the prompt arrow needs to be displayed
                showArrow: true,
                // did one of the validation fail ? kept global to stop further ajax validations
                isError: false,
                // Limit how many displayed errors a field can have
                maxErrorsPerField: false,
                
                // Caches field validation status, typically only bad status are created.
                // the array is used during ajax form validation to detect issues early and prevent an expensive submit
                ajaxValidCache: {},
                // Auto update prompt position after window resize
                autoPositionUpdate: false,

                InvalidFields: [],
                onFieldSuccess: false,
                onFieldFailure: false,
                onSuccess: false,
                onFailure: false,
                validateAttribute: "class",
                addSuccessCssClassToField: "",
                addFailureCssClassToField: "",
                
                // Auto-hide prompt
                autoHidePrompt: false,
                // Delay before auto-hide
                autoHideDelay: 10000,
                // Fade out duration while hiding the validations
                fadeDuration: 0.3,
         // Use Prettify select library
         prettySelect: false,
         // Add css class on prompt
         addPromptClass : "",
         // Custom ID uses prefix
         usePrefix: "",
         // Custom ID uses suffix
         useSuffix: "",
         // Only show one message per error prompt
         showOneMessage: false
        }};
        $(function(){$.validationEngine.defaults.promptPosition = methods.isRTL()?'topLeft':"topRight"});
})(jQuery);