/*

Overview
========
This script handles all form validations and depends on jQuery 1.5+.
By default the validation script will hook onto all forms but first
checks if there are validatables contained within the form before 
doing validation checks. Validatables are basically any visible form 
elements with the data-validate attribute set.

The validation script uses a series of data hooks. The list of 
available hooks are:

    data-validate="{required|email|match}"
    data-message="{custom error message}"
    data-match="{selector}"
    data-show="{selector}"
    data-hide="{selector}|onload"


Explanation of Hooks
====================

The validate hook [data-validate="{string}"]
--------------------------------------------
This is the most important hook the validation script look at to initiate
validation on a form element. The parameters accepted are 
"required", "email" or "match".

"required" is used when you want a required field

"email" is used when you want to validate the field as email

"match" is used when you want to match the field with another element and 
should be used together with [data-match] which is explained below.


The message hook [data-message="{string}"]
------------------------------------------
This hook gives you the ability to provide a custom error message should
the default ones not satisfy your needs. Simply use this along with the 
[data-validate] hook on the same element to have a custom error message.

The match hook [data-match="{selector}"]
----------------------------------------
This hook gives you match ability on fields such as re-type emails and
password confirm inputs. The [data-match] should be used together with
[data-validate="match"]. The match selector accepts any css selector, 
we recommend using id selectors for better performance.

The show hook [data-show="{selector}"]
--------------------------------------
This hook binds to the click event of the element it is placed on and will 
slide down the target selector. The selector accepts any css selector, 
id selectors recommended for performance reasons. 

The hide hook [data-hide="{selector}|onload"]
---------------------------------------------
This hook binds to the click event of the element it is placed on and will 
slide up the target selector. The selector accepts any css selector, 
id selectors recommended for performance reasons. 

If the [data-hide] is placed on a element as data-hide="onload" the element
will be hidden on page load.


Usage
=====

1) Add scripts within the HTML <head>. Place them after style and link tags!

    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
    <script type="text/javascript" src="includes/shared/js/form.js" language="javascript"></script>

2) Add appropriate hooks to activate validations.

To make a text input required you will need to use the data-validate 
attribute and pass it a string "required". e.g.

    <label for="firstname">First name*</label>
    <input type="text" id="firstname" data-validate="required" />

Note the <label> element is required and is used by the validation
script to display a meaningful error message to the user.

data-validate is also used to make a group of radios or checkboxes required. 
To do this you simply wrap the group of elements in question with a container
that has the data-validate="required" attribute, e.g.

    <ol data-validate="required" data-message="Please let us know Yes, No or Maybe?">
        <li><label><input type="radio" name="answer" value="Yes" />Yes</label></li>
        <li><label><input type="radio" name="answer" value="No" />No</label></li>
        <li><label><input type="radio" name="answer" value="Maybe" />Maybe</label></li>
    </ol>

Note the data-message attribute in the container. This is used to display a meaningful
error message to the user. If data-message is not available the error that is required
is "Please fill in the required field.".

The following input shows how you can do a match on a password_confirm field to verify
if it matches with the password field with id="password":
 
    <input type="text" id="password_confirm" data-validate="match" data-match="#password" />

The following will hide a element on page load:

    <div id="show_me" data-hide="onload">
      <!-- hide me! -->
    </div>

The following will show the show_me div above on checking the checkbox/radio:

    <input type="checkbox" data-show="#show_me" />
    <input type="radio" data-show="#show_me" />

The following will hide the show_me div above on un-checking the checkbox:

    <input type="checkbox" data-hide="#show_me" />

You can combine [data-show] and [data-hide] on the same element to achieve accordion
style show/hide effects, e.g.

  <!-- on click show #div1 and hide #div2 -->
  <input type="radio" value="Yes" name="answer" data-show="#div1" data-hide="#div2" />
  
  <!-- on click show #div2 and hide #div1 -->
  <input type="radio" value="No" name="answer" data-show="#div2" data-hide="#div1" />

*/

(function($) {

  // define $.ubs object
  $.ubs = {};

  // extend the $.ubs object
  $.extend($.ubs, {
    init: function( $form ) {

      // form setup - hide containers onload
      $('[data-hide="onload"]').hide();

      // bind click on elements with [data-show] and [data-hide]
      $('[data-show], [data-hide]').click(function() {
        if ($(this).is(':checkbox')) {
          $( $( this ).data('show') )[ $(this).is(':checked') ? 'slideDown' : 'slideUp']('slow');
          $( $( this ).data('hide') )[ $(this).is(':checked') ? 'slideUp' : 'slideDown']('slow');
        } else {
          $( $( this ).data('show') ).slideDown('slow');
          $( $( this ).data('hide') ).slideUp('slow');
        }
      });

      // form submit
      $form.submit( function() {
        var $validatables = $( '[data-validate]:visible', $form );
        
        // exist if there are no validatable fields within this form
        if ( !$validatables.length ) {
          return;
        }

        var error = '';

        $validatables.each( function() {

          var $this = $( this ),
            vtype = $(this).data('validate').split('|') || '';
            $label = $('label[for="'+ $this[0].id +'"]'),
            labelText = $.trim( $label.text().replace("*", "") ),
            val = $this.val() || $this.text(),
            matchVal = $( $(this).data('match') ).val() || '',
            message = $this.data('message') || '';

            for (var i=0; i<vtype.length; i++) {

              // if there are child elements this is most likely a checkbox or radio group
              var $childInputs = $this.find(':checkbox, :radio');
              if ( vtype[i] === 'required' && $childInputs.length && $childInputs.filter(':checked').length === 0) {
                error = 'Please fill in the required field.';
              }

              else if ( vtype[i] === 'required' && $.ubs.isBlank( val ) ) {
                error = 'Please enter a value for the "' + labelText + '" field.';
              }

              else if ( vtype[i] === 'email' && !$.ubs.isEmail( val ) ) {
                error = 'Please enter a complete email address in the form:\nyourname@ubs.com';
              }

              else if ( vtype[i] === 'match' && !$.ubs.isMatch( val, matchVal ) ) {
                error = 'Please enter a matching email address.';
              }
              
              // if there's an error we'll alert the user, focus on the element in question
              // and exit the data-validate loop.
              if ( error ) {
                alert( message ? message : error );
                $this.focus();
                return false;
              }
            }

        });

        // submit form if no errors.
        return error === '';
      });

    },
    isEmail: function( val ) {
      return /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/.test( val );
    },
    isBlank: function( val ) {
      return $.trim(val + ' ') === '';
    },
    isMatch: function( val1, val2 ) {
      return val1 === val2;
    }
  });

  $.fn.ubsForm = function() {
    return this.each( function() {
      $.ubs.init( $( this ) );
    });
  }
  
})(jQuery);


jQuery(function($){

  // on DOMReady initialize the UBS form validator for all <form> elements.
  $('form').ubsForm();

});
