Html5實現(xiàn)用戶注冊自動校驗功能實例代碼

字號:


    這篇文章主要介紹了 Html5實現(xiàn)用戶注冊自動校驗功能實例代碼的相關(guān)資料,需要的朋友可以參考下
    抽時間寫了一個帶有自動校驗功能的Html5用戶注冊Demo。使用到Handlebars模板技術(shù)和手機驗證碼校驗。
    以下是效果截圖:
    名單
    1.頁面代碼:usersRegister.hbs
    XML/HTML Code
    <!DOCTYPE html>     
    <!--[if IE 8 ]> <html lang="en"> <![endif]-->     
    <!--[if IE 9 ]> <html lang="en"> <![endif]-->     
    <!--[if (gt IE 9)|!(IE)]><!-->     
    <html lang="en">     
    <!--<![endif]-->     
    <head>     
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">     
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />     
        <title>用戶注冊</title>     
        <!--[if lt IE 9]>     
        <script src="/assets/scripts/html5shiv.js"></script>     
        <![endif]-->     
        <link href="/assets/styles/jquery.idealforms.min.css" rel="stylesheet" media="screen" />     
        <style type="text/css">     
            body {     
                font: normal 15px/1.5 Arial, Helvetica, Free Sans, sans-serif;     
                color: #222;     
                overflow-y: scroll;     
                padding: 60px 0 0 0;     
            }     
            .main {     
                width: 560px;     
                height: 480px;     
                margin: -50px auto;     
            }     
            #my-form {     
                width: 560px;     
                height: 450px;     
                margin: 0 auto;     
                border: 1px solid #ccc;     
                padding: 3em;     
                border-radius: 3px;     
                box-shadow: 0 0 2px rgba(0, 0, 0, .2);     
            }     
        </style>     
        <script type="text/javascript" src="/assets/scripts/jquery-1.8.2.min.js"></script>     
        <script type="text/javascript" src="/assets/scripts/jquery.idealforms.js"></script>     
    </head>     
    <body>     
    <!--main" >     
            <div> 歡迎您注冊!</div>     
            <!-- Begin Form -->     
            <form id="my-form">     
                <div>     
                    <label>用戶名:</label><input id="username" name="username" type="text" />     
                </div>     
                <div>     
                    <!-- <label>密碼:</label><input id="pass" name="password" type="password" /> -->     
                    <label>密碼:</label><input id="pass" name="password" type="text" />     
                </div>     
                <div>     
                    <label>郵箱:</label><input id="email" name="email"     
                                             data-ideal="required email" type="email" />     
                </div>     
                <div>     
                    <label>電話:</label><input id="telephone" type="text" name="phone" data-ideal="phone" />     
                </div>     
                <div>     
                    <label>供應(yīng)商V碼:</label><input id="vCode" type="text" name="vCode" data-ideal="vCode" />     
                </div>     
                <div>     
                    <label>真實姓名:</label><input id="trueName" type="text" name="trueName" data-ideal="trueName" />     
                </div>     
                <div>     
                    <label>手機驗證碼:</label><input id="telCode" type="text" name="telCode" data-ideal="telCode" />     
                </div>     
                <div>     
                    <button id="getTelCode" type="button" >獲取手機校驗碼</button>     
                    <hr />     
                </div>     
                <!--<div>     
                    <label>性別:</label>     
                    <select id="sex" name="sex">     
                        <option value="男">男</option>     
                        <option value="女">女</option>     
                    </select>     
                </div>     
                <div>     
                    <label>昵稱:</label><input id="nickName" type="text" name="nickName" data-ideal="nickName" />     
                </div>     
                <div>     
                    <label>年齡:</label><input id="age" type="text" name="age" data-ideal="age" />     
                </div>-->     
                <!-- <div>     
                    <label>地址:</label><input type="text" name="address" data-ideal="address" />     
                </div>     
                <div>     
                    <label>QQ:</label><input type="text" name="qq" data-ideal="qq" />     
                </div>     
                <div>     
                    <label>郵編:</label><input type="text" name="zip" data-ideal="zip" />     
                </div>     
                <div>     
                    <label>傳真:</label><input type="text" name="fax" data-ideal="fax" />     
                </div>     
                <div>     
                    <label>身份證:</label><input type="text" name="creditID" data-ideal="creditID" />     
                </div>     
                <div>     
                    <label>出生日期:</label><input name="date"     
                        data-ideal="date" type="text" placeholder="月/日/年" />     
                </div>     
                <div>     
                    <label>上傳頭像:</label><input id="file" name="file" multiple     
                        type="file" />     
                </div>     
                <div>     
                    <label>個人主頁:</label><input name="website" data-ideal="url"     
                        type="text" />     
                </div>     
                <div>     
                    <label>備注:</label>     
                    <textarea id="comments" name="comments"></textarea>     
                </div>     
                -->     
                <!-- <div id="languages">     
                    <label>語言:</label> <label><input type="checkbox"     
                        name="langs[]" value="English" />英文</label> <label><input     
                        type="checkbox" name="langs[]" value="Chinese" />中文</label> <label><input     
                        type="checkbox" name="langs[]" value="Spanish" />西班牙文</label> <label><input     
                        type="checkbox" name="langs[]" value="French" />法文</label>     
                </div>     
                <div>     
                    <label>精通幾門:</label> <label><input type="radio"     
                        name="radio" checked />1</label> <label><input type="radio"     
                        name="radio" />2</label> <label><input type="radio" name="radio" />3</label>     
                    <label><input type="radio" name="radio" />4</label>     
                </div>     
                <div>     
                    <label>國籍:</label> <select id="states" name="states">     
                        <option value="default">– 選擇國籍 –</option>     
                        <option value="AL">阿拉伯</option>     
                        <option value="AK">中國</option>     
                        <option value="AZ">美國</option>     
                        <option value="AR">法國</option>     
                        <option value="CA">英國</option>     
                        <option value="CO">德國</option>     
                        <option value="CT">西班牙</option>     
                        <option value="DE">俄羅斯</option>     
                    </select>     
                </div> -->     
                <div>     
                    <button type="button" id="submit">提交</button>     
                    <button id="reset" type="button" >重置</button>     
                </div>     
            </form>     
            <!-- End Form -->     
        </div>     
    <script type="text/javascript">     
        var options = {     
            onFail : function() {     
                alert($myform.getInvalid().length + ' invalid fields.')     
            },     
            inputs : {     
                'password' : {     
                    filters : 'required pass'     
                },     
                'username' : {     
                    filters : 'required username'     
                },     
                'email' : {     
                    filters : 'required email'     
                },     
                'phone' : {     
                    filters : 'required phone'     
                },     
                'trueName' : {     
                    filters : 'required'     
                },     
                'vCode' : {     
                    filters : 'required'     
                },     
                'telCode' : {     
                    filters : 'required'     
                }     
                /*     
                'age' : {     
                    filters : 'required digits',     
                    data : {     
                       min : 16,     
                       max : 70     
                    }     
                },     
                'file' : {     
                    filters : 'extension',     
                    data : {     
                        extension : [ 'jpg' ]     
                    }     
                },     
                'comments' : {     
                    filters : 'min max',     
                    data : {     
                        min : 50,     
                        max : 200     
                    }     
                },     
                'states' : {     
                    filters : 'exclude',     
                    data : {     
                        exclude : [ 'default' ]     
                    },     
                    errors : {     
                        exclude : '選擇國籍.'     
                    }     
                },     
                'langs[]' : {     
                    filters : 'min max',     
                    data : {     
                        min : 2,     
                        max : 3     
                    },     
                    errors : {     
                        min : 'Check at least <strong>2</strong> options.',     
                        max : 'No more than <strong>3</strong> options allowed.'     
                    }     
                }     
                */     
            }     
        };     
        $('#getTelCode').click(function() {     
            var telephone = document.getElementById("telephone").value;   //手機號碼     
            if (telephone == null || telephone == ""){     
                alert("手機號碼不能為空!");     
            }     
            else{     
                $.ajax({     
                    type : "GET",     
                    dataType : "json",     
                    url : "../api/getTelCode?telephone="+ telephone,     
                    success : function(msg) {     
                    },     
                    error : function(e) {     
                        alert("獲取手機校驗碼失??!" + e);     
                    }     
                });     
            }     
        });     
        var $myform = $('#my-form').idealforms(options).data('idealforms');     
        $('#submit').click(function() {     
            var username = document.getElementById("username").value; //用戶名     
            var password = document.getElementById("pass").value;    //密碼     
            var email = document.getElementById("email").value;     //郵箱     
            var telephone = document.getElementById("telephone").value;     //手機號碼     
            var vCode = document.getElementById("vCode").value;     //公司V碼     
            var telCode = document.getElementById("telCode").value;     //手機校驗碼     
            var trueName = document.getElementById("trueName").value;     //真實姓名     
            $.ajax({     
                type : "GET",     
                url : "../api/usersRegister?username="+ username +"password="+ password +"email="+ email +"telephone="+ telephone +"vCode="+ vCode +"telCode="+ telCode +"trueName="+ trueName,     
                success : function(msg) {     
                   //獲取當(dāng)前網(wǎng)址,如: http://localhost:8083/uimcardprj/share/meun.jsp     
                   var curWwwPath = window.document.location.href;     
                   //獲取主機地址之后的目錄,如: uimcardprj/share/meun.jsp     
                   var pathName = window.document.location.pathname;     
                   var pos = curWwwPath.indexOf(pathName);     
                   //獲取主機地址,如: http://localhost:8083     
                   var localhostPaht = curWwwPath.substring(0, pos);     
                   //獲取帶"/"的項目名,如:/uimcardprj     
                   var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);     
                   window.location.href = projectName + "/login";     
                   alert("注冊成功!");     
                },     
                error : function(e) {     
                    alert("注冊失??!" + e);     
                }     
            });     
        });     
        $('#reset').click(function() {     
            $myform.reset().fresh().focusFirst();     
        });     
    </script>     
    </body>     
    </html>    
    2.jq輸入校驗:jquery.idealforms.js
    該js校驗初始版本來自Cedric Ruiz,我略有修改。
    部分校驗的規(guī)則如下:
    required: '此處是必填的.'
    number: '必須是數(shù)字.',
    digits: '必須是唯一的數(shù)字.'
    name: '必須至少有3個字符長,并且只能包含字母.'
    username: '用戶名最短5位,最長30位,請使用英文字母、數(shù)字、中文和下劃線. 用戶名首字符必須為字母、數(shù)字、中文,不能為全數(shù)字.中文最長21個字.'
    pass: '密碼的位數(shù)必須的在6-15位之間,并且至少包含一個數(shù)字,一個大寫字母和一個小寫字母.'
    strongpass: '必須至少為8個字符長,至少包含一個大寫字母和一個小寫字母和一個數(shù)字或特殊字符.'
    email: '必須是一個有效的email地址. <em>(例: user@gmail.com)</em>'
    phone: '必須是一個有效的手機號碼. <em>(例: 18723101212)</em>'
    以下是整個代碼文件:
    XML/HTML Code
    /*--------------------------------------------------------------------------    
      jq-idealforms 2.1    
      * Author: Cedric Ruiz    
      * License: GPL or MIT    
      * Demo: http://elclanrs.github.com/jq-idealforms/    
      *    
    --------------------------------------------------------------------------*/     
    ;(function ( $, window, document, undefined ) {     
      'use strict';     
      // Global Ideal Forms namespace     
      $.idealforms = {}     
      $.idealforms.filters = {}     
      $.idealforms.errors = {}     
      $.idealforms.flags = {}     
      $.idealforms.ajaxRequests = {}     
    /*--------------------------------------------------------------------------*/     
    /**    
     * @namespace A chest for various Utils    
     */     
    var Utils = {     
      /**    
       * Get width of widest element in the collection.    
       * @memberOf Utils    
       * @param {jQuery object} $elms    
       * @returns {number}    
       */     
      getMaxWidth: function( $elms ) {     
        var maxWidth = 0     
        $elms.each(function() {     
          var width = $(this).outerWidth()     
          if ( width > maxWidth ) {     
            maxWidth = width     
          }     
        })     
        return maxWidth     
      },     
      /**    
       * Hacky way of getting LESS variables    
       * @memberOf Utils    
       * @param {string} name The name of the LESS class.    
       * @param {string} prop The css property where the data is stored.    
       * @returns {number, string}    
       */     
      getLessVar: function( name, prop ) {     
        var value = $('<p></p>').hide().appendTo('body').css( prop )     
        $('.' + name).remove()     
        return ( /^\d+/.test( value ) ? parseInt( value, 10 ) : value )     
      },     
      /**    
       * Like ES5 Object.keys    
       */     
      getKeys: function( obj ) {     
        var keys = []     
        for(var key in obj) {     
          if ( obj.hasOwnProperty( key ) ) {     
            keys.push( key )     
          }     
        }     
        return keys     
      },     
      // Get lenght of an object     
      getObjSize: function( obj ) {     
        var size = 0, key;     
        for ( key in obj ) {     
          if ( obj.hasOwnProperty( key ) ) {     
            size++;     
          }     
        }     
        return size;     
      },     
      isFunction: function( obj ) {     
        return typeof obj === 'function'     
      },     
      isRegex: function( obj ) {     
        return obj instanceof RegExp     
      },     
      isString: function( obj ) {     
        return typeof obj === 'string'     
      },     
      getByNameOrId: function( str ) {     
        var $el = $('[name="'+ str +'"]').length     
          ? $('[name="'+ str +'"]') // by name     
          : $('#'+ str) // by id     
        return $el.length     
          ? $el     
          : $.error('The field "'+ str + '" doesn\'t exist.')     
      },     
      getFieldsFromArray: function( fields ) {     
        var f = []     
        for ( var i = 0, l = fields.length; i < l; i++ ) {     
          f.push( Utils.getByNameOrId( fields[i] ).get(0) )     
        }     
        return $( f )     
      },     
      convertToArray: function( obj ) {     
        return Object.prototype.toString.call( obj ) === '[object Array]'     
          ? obj : [ obj ]     
      },     
      /**    
       * Determine type of any Ideal Forms element    
       * @param $input jQuery $input object    
       */     
      getIdealType: function( $el ) {     
        var type = $el.attr('type') || $el[0].tagName.toLowerCase()     
        return (     
          /(text|password|email|number|search|url|tel|textarea)/.test( type ) && 'text' ||     
          /file/.test( type ) && 'file' ||     
          /select/.test( type ) && 'select' ||     
          /(radio|checkbox)/.test( type ) && 'radiocheck' ||     
          /(button|submit|reset)/.test( type ) && 'button' ||     
          /h\d/.test( type ) && 'heading' ||     
          /hr/.test( type ) && 'separator' ||     
          /hidden/.test( type ) && 'hidden'     
        )     
      },     
      /**    
       * Generates an input    
       * @param name `name` attribute of the input    
       * @param type `type` or `tagName` of the input    
       */     
      makeInput: function( name, value, type, list, placeholder ) {     
        var markup, items = [], item, i, len     
        function splitValue( str ) {     
          var item, value, arr     
          if ( /::/.test( str ) ) {     
            arr = str.split('::')     
            item = arr[ 0 ]     
            value = arr[ 1 ]     
          } else {     
            item = value = str     
          }     
          return { item: item, value: value }     
        }     
        // Text & file     
        if ( /^(text|password|email|number|search|url|tel|file|hidden)$/.test(type) )     
          markup = '<input '+     
            'type="'+ type +'" '+     
            'id="'+ name +'" '+     
            'name="'+ name +'" '+     
            'value="'+ value +'" '+     
            (placeholder && 'placeholder="'+ placeholder +'"') +     
            '/>'     
        // Textarea     
        if ( /textarea/.test( type ) ) {     
          markup = '<textarea id="'+ name +'" name="'+ name +'" value="'+ value +'"></textarea>'     
        }     
        // Select     
        if ( /select/.test( type ) ) {     
          items = []     
          for ( i = 0, len = list.length; i < len; i++ ) {     
            item = splitValue( list[ i ] ).item     
            value = splitValue( list[ i ] ).value     
            items.push('<option value="'+ value +'">'+ item +'</option>')     
          }     
          markup =     
            '<select id="'+ name +'" name="'+ name +'">'+     
              items.join('') +     
            '</select>'     
        }     
        // Radiocheck     
        if ( /(radio|checkbox)/.test( type ) ) {     
          items = []     
          for ( i = 0, len = list.length; i < len; i++ ) {     
            item = splitValue( list[ i ] ).item     
            value = splitValue( list[ i ] ).value     
            items.push(     
              '<label>'+     
                '<input type="'+ type +'" name="'+ name +'" value="'+ value +'" />'+     
                item +     
              '</label>'     
            )     
          }     
          markup = items.join('')     
        }     
        return markup     
      }     
    }     
    /**    
     * Custom tabs for Ideal Forms    
     */     
    $.fn.idealTabs = function (container) {     
      var     
      // Elements     
      $contents = this,     
      $containercontainer = container,     
      $wrapper = $('<ul/>'),     
      $tabs = (function () {     
        var tabs = []     
        $contents.each(function () {     
          var name = $(this).attr('name')     
          var html =     
            '<li>'+     
              '<span>' + name + '</span>'+     
              '<i>0</i>'+     
            '</li>'     
          tabs.push(html)     
        })     
        return $(tabs.join(''))     
      }()),     
      Actions = {     
        getCurIdx: function () {     
          return $tabs     
            .filter('.ideal-tabs-tab-active')     
            .index()     
        },     
        getTabIdxByName: function (name) {     
          var re = new RegExp(name, 'i')     
          var $tab = $tabs.filter(function () {     
            return re.test($(this).text())     
          })     
          return $tab.index()     
        }     
      },     
      /**    
       * Public methods    
       */     
      Methods = {     
        /**    
         * Switch tab    
         */     
        switchTab: function (nameOrIdx) {     
          var idx = Utils.isString(nameOrIdx)     
            ? Actions.getTabIdxByName(nameOrIdx)     
            : nameOrIdx     
          $tabs.removeClass('ideal-tabs-tab-active')     
          $tabs.eq(idx).addClass('ideal-tabs-tab-active')     
          $contents.hide().eq(idx).show()     
        },     
        nextTab: function () {     
          var idx = Actions.getCurIdx() + 1     
          idx > $tabs.length - 1     
            ? Methods.firstTab()     
            : Methods.switchTab(idx)     
        },     
        prevTab: function () {     
          Methods.switchTab(Actions.getCurIdx() - 1)     
        },     
        firstTab: function () {     
          Methods.switchTab(0)     
        },     
        lastTab: function () {     
          Methods.switchTab($tabs.length - 1)     
        },     
        updateCounter: function (nameOrIdx, text) {     
          var idx = !isNaN(nameOrIdx) ? nameOrIdx : Actions.getTabIdxByName(name),     
              $counter = $tabs.eq(idx).find('.ideal-tabs-tab-counter')     
          $counter.removeClass('ideal-tabs-tab-counter-zero')     
          if (!text) {     
            $counter.addClass('ideal-tabs-tab-counter-zero')     
          }     
          $counter.html(text)     
        }     
      }     
      // Attach methods     
      for (var m in Methods)     
        $contents[m] = Methods[m]     
      // Init     
      $tabs.first()     
        .addClass('ideal-tabs-tab-active')     
        .end()     
        .click(function () {     
          var name = $(this).text()     
          $contents.switchTab(name)     
        })     
      // Insert in DOM & Events     
      $wrapper.append($tabs).appendTo($container)     
      $contents.addClass('ideal-tabs-content')     
      $contents.each(function () {     
        var $this = $(this), name = $(this).attr('name')     
        $this.data('ideal-tabs-content-name', name)     
          .removeAttr('name')     
      })     
      $contents.hide().first().show() // Start fresh     
      return $contents     
    }     
    /**    
     * A custom <select> menu jQuery plugin    
     * @example `$('select').idealSelect()`    
     */     
    $.fn.idealSelect = function () {     
      return this.each(function () {     
        var     
        $select = $(this),     
        $options = $select.find('option')     
        /**    
         * Generate markup and return elements of custom select    
         * @memberOf $.fn.toCustomSelect    
         * @returns {object} All elements of the new select replacement    
         */     
        var idealSelect = (function () {     
          var     
          $wrap = $('<ul/>'),     
          $menu = $(     
            '<li><span>' +     
              $options.filter(':selected').text() +     
            '</span></li>'     
          ),     
          items = (function () {     
            var items = []     
            $options.each(function () {     
              var $this = $(this)     
              items.push('<li>' + $this.text() + '</li>')     
            })     
            return items     
          }())     
          $menu.append('<ul>' + items.join('') + '</ul>')     
          $wrap.append($menu)     
          return {     
            select: $wrap,     
            title: $menu.find('.ideal-select-title'),     
            sub: $menu.find('.ideal-select-sub'),     
            items: $menu.find('.ideal-select-item')     
          }     
        }())     
        /**    
         * @namespace Methods of custom select    
         * @memberOf $.fn.toCustomSelect    
         */     
        var Actions = {     
          getSelectedIdx: function () {     
            return idealSelect.items     
              .filter('.ideal-select-item-selected').index()     
          },     
          /**    
           * @private    
           */     
          init: (function () {     
            $select.css({     
              position: 'absolute',     
              left: '-9999px'     
            })     
            idealSelect.sub.hide()     
            idealSelect.select.insertAfter($select)     
            idealSelect.select.css(     
              'min-width',     
              Utils.getMaxWidth(idealSelect.items)     
            )     
            idealSelect.items     
              .eq($options.filter(':selected').index())     
              .addClass('ideal-select-item-selected')     
          }()),     
          noWindowScroll: function (e) {     
            if (e.which === 40 || e.which === 38 || e.which === 13) {     
              e.preventDefault()     
            }     
          },     
          // Fix loosing focus when scrolling     
          // and selecting item with keyboard     
          focusHack: function () {     
            setTimeout(function () {     
              $select.trigger('focus')     
            }, 1)     
          },     
          focus: function () {     
            idealSelect.select.addClass('ideal-select-focus')     
            $(document).on('keydown.noscroll', Actions.noWindowScroll)     
          },     
          blur: function () {     
            idealSelect.select     
              .removeClass('ideal-select-open ideal-select-focus')     
            $(document).off('.noscroll')     
          },     
          scrollIntoView: function (dir) {     
            var     
            $selected = idealSelect.items.filter('.ideal-select-item-selected'),     
            itemHeight = idealSelect.items.outerHeight(),     
            menuHeight = idealSelect.sub.outerHeight(),     
            isInView = (function () {     
              // relative position to the submenu     
              var elPos = $selected.position().top + itemHeight     
              return dir === 'down'     
                ? elPos <= menuHeight     
                : elPos > 0     
            }())     
            if (!isInView) {     
              itemHeight = (dir === 'down')     
                ? itemHeight // go down     
                : -itemHeight // go up     
              idealSelect.sub     
                .scrollTop(idealSelect.sub.scrollTop() + itemHeight)     
            }     
          },     
          scrollToItem: function () {     
            var idx = Actions.getSelectedIdx(),     
                height = idealSelect.items.outerHeight(),     
                nItems = idealSelect.items.length,     
                allHeight = height * nItems,     
                curHeight = height * (nItems - idx)     
            idealSelect.sub.scrollTop(allHeight - curHeight)     
          },     
          showMenu: function () {     
            idealSelect.sub.fadeIn('fast')     
            idealSelect.select.addClass('ideal-select-open')     
            Actions.select(Actions.getSelectedIdx())     
            Actions.scrollToItem()     
          },     
          hideMenu: function () {     
            idealSelect.sub.hide()     
            idealSelect.select.removeClass('ideal-select-open')     
          },     
          select: function (idx) {     
            idealSelect.items     
              .removeClass('ideal-select-item-selected')     
            idealSelect.items     
              .eq(idx).addClass('ideal-select-item-selected')     
          },     
          change: function (idx) {     
            var text = idealSelect.items.eq(idx).text()     
            Actions.select(idx)     
            idealSelect.title.text(text)     
            $options.eq(idx).prop('selected', true)     
            $select.trigger('change')     
          },     
          keydown: function (key) {     
            var     
            idx = Actions.getSelectedIdx(),     
            isMenu = idealSelect.select.is('.ideal-select-menu'),     
            isOpen = idealSelect.select.is('.ideal-select-open')     
            /**    
             * @namespace Key pressed    
             */     
            var keys = {     
              9: function () { // TAB     
                if (isMenu) {     
                  Actions.blur()     
                  Actions.hideMenu()     
                }     
              },     
              13: function () { // ENTER     
                if (isMenu)     
                  isOpen     
                    ? Actions.hideMenu()     
                    : Actions.showMenu()     
                Actions.change(idx)     
              },     
              27: function () { // ESC     
                if (isMenu) Actions.hideMenu()     
              },     
              40: function () { // DOWN     
                if (idx < $options.length - 1) {     
                  isOpen     
                    ? Actions.select(idx + 1)     
                    : Actions.change(idx + 1)     
                }     
                Actions.scrollIntoView('down')     
              },     
              38: function () { // UP     
                if (idx > 0) {     
                  isOpen     
                    ? Actions.select(idx - 1)     
                    : Actions.change(idx - 1)     
                }     
                Actions.scrollIntoView('up')     
              },     
              'default': function () { // Letter     
                var     
                letter = String.fromCharCode(key),     
                $matches = idealSelect.items     
                  .filter(function () {     
                    return /^\w+$/i.test( letter ) && // not allow modifier keys ( ctrl, cmd, meta, super... )     
                      new RegExp('^' + letter, 'i').test( $(this).text() ) // find first match     
                  }),     
                nMatches = $matches.length,     
                counter = idealSelect.select.data('counter') + 1 || 0,     
                curKey = idealSelect.select.data('key') || key,     
                newIdx = $matches.eq(counter).index()     
                if (!nMatches) // No matches     
                  return false     
                // If more matches with same letter     
                if (curKey === key) {     
                  if (counter < nMatches) {     
                    idealSelect.select.data('counter', counter)     
                  }     
                  else {     
                    idealSelect.select.data('counter', 0)     
                    newIdx = $matches.eq(0).index()     
                  }     
                }     
                // If new letter     
                else {     
                  idealSelect.select.data('counter', 0)     
                  newIdx = $matches.eq(0).index()     
                }     
                if (isOpen)     
                  Actions.select(newIdx)     
                else     
                  Actions.change(newIdx)     
                idealSelect.select.data('key', key)     
                Actions.scrollToItem()     
                Actions.focusHack()     
              }     
            }     
            keys[key]     
              ? keys[key]()     
              : keys['default']()     
          }     
        }     
        /**    
         * @namespace Holds all events of custom select for "menu mode" and "list mode"    
         * @memberOf $.fn.toCustomSelect    
         */     
        var events = {     
          focus: Actions.focus,     
          'blur.menu': function () {     
            Actions.blur()     
            Actions.hideMenu()     
          },     
          'blur.list': function () {     
            Actions.blur()     
          },     
          keydown: function (e) {     
            Actions.keydown(e.which)     
          },     
          'clickItem.menu': function () {     
            Actions.change($(this).index())     
            Actions.hideMenu()     
          },     
          'clickItem.list': function () {     
            Actions.change($(this).index())     
          },     
          'clickTitle.menu': function () {     
            Actions.focus()     
            Actions.showMenu()     
            $select.trigger('focus')     
          },     
          'hideOutside.menu': function () {     
            $select.off('blur.menu')     
            $(document).on('mousedown.ideal', function (evt) {     
              if (!$(evt.target).closest(idealSelect.select).length) {     
                $(document).off('mousedown.ideal')     
                $select.on('blur.menu', events['blur.menu'])     
              } else {     
                Actions.focusHack()     
              }     
            })     
          },     
          'mousedown.list': function () {     
            Actions.focusHack()     
          }     
        }     
        // Reset events     
        var disableEvents = function () {     
          idealSelect.select.removeClass('ideal-select-menu ideal-select-list')     
          $select.off('.menu .list')     
          idealSelect.items.off('.menu .list')     
          idealSelect.select.off('.menu .list')     
          idealSelect.title.off('.menu .list')     
        }     
        // Menu mode     
        idealSelect.select.on('menu', function () {     
          disableEvents()     
          idealSelect.select.addClass('ideal-select-menu')     
          Actions.hideMenu()     
          $select.on({     
            'blur.menu': events['blur.menu'],     
            'focus.menu': events.focus,     
            'keydown.menu': events.keydown     
          })     
          idealSelect.select.on('mousedown.menu', events['hideOutside.menu'])     
          idealSelect.items.on('click.menu', events['clickItem.menu'])     
          idealSelect.title.on('click.menu', events['clickTitle.menu'])     
        })     
        // List mode     
        idealSelect.select.on('list', function () {     
          disableEvents()     
          idealSelect.select.addClass('ideal-select-list')     
          Actions.showMenu()     
          $select.on({     
            'blur.list': events['blur.list'],     
            'focus.list': events.focus,     
            'keydown.list': events.keydown     
          })     
          idealSelect.select.on('mousedown.list', events['mousedown.list'])     
          idealSelect.items.on('mousedown.list', events['clickItem.list'])     
        })     
        $select.keydown(function (e) {     
          // Prevent default keydown event     
          // to avoid bugs with Ideal Select events     
          if (e.which !== 9) e.preventDefault()     
        })     
        // Reset     
        idealSelect.select.on('reset', function(){     
          Actions.change(0)     
        })     
        idealSelect.select.trigger('menu') // Default to "menu mode"     
      })     
    }     
    /*    
     * idealRadioCheck: jQuery plguin for checkbox and radio replacement    
     * Usage: $('input[type=checkbox], input[type=radio]').idealRadioCheck()    
     */     
    $.fn.idealRadioCheck = function() {     
      return this.each(function() {     
        var $this = $(this)     
        var $span = $('<span/>')     
        $span.addClass( 'ideal-'+ ( $this.is(':checkbox') ? 'check' : 'radio' ) )     
        $this.is(':checked') && $span.addClass('checked') // init     
        $span.insertAfter( $this )     
        $this.parent('label').addClass('ideal-radiocheck-label')     
          .attr('onclick', '') // Fix clicking label in iOS     
        $this.css({ position: 'absolute', left: '-9999px' }) // hide by shifting left     
        // Events     
        $this.on({     
          change: function() {     
            var $this = $(this)     
            if ( $this.is('input[type="radio"]') ) {     
              $this.parent().siblings('label').find('.ideal-radio').removeClass('checked')     
            }     
            $span.toggleClass( 'checked', $this.is(':checked') )     
          },     
          focus: function() { $span.addClass('focus') },     
          blur: function() { $span.removeClass('focus') },     
          click: function() { $(this).trigger('focus') }     
        })     
      })     
    }     
    ;(function( $ ) {     
      // Browser supports HTML5 multiple file?     
      var multipleSupport = typeof $('<input/>')[0].multiple !== 'undefined',     
          isIE = /msie/i.test( navigator.userAgent )     
      $.fn.idealFile = function() {     
        return this.each(function() {     
          var $file = $(this).addClass('ideal-file'), // the original file input     
              // label that will be used for IE hack     
              $wrap = $('<div>'),     
              $input = $('<input type="text" />'),     
              // Button that will be used in non-IE browsers     
              $button = $('<button type="button">Open</button>'),     
              // Hack for IE     
              $label = $('<label for="'+ $file[0].id +'">Open</label>')     
          // Hide by shifting to the left so we     
          // can still trigger events     
          $file.css({     
            position: 'absolute',     
            left: '-9999px'     
          })     
          $wrap.append( $input, ( isIE ? $label : $button ) ).insertAfter( $file )     
          // Prevent focus     
          $file.attr('tabIndex', -1)     
          $button.attr('tabIndex', -1)     
          $button.click(function () {     
            $file.focus().click() // Open dialog     
          })     
          $file.change(function() {     
            var files = [], fileArr, filename     
            // If multiple is supported then extract     
            // all filenames from the file array     
            if ( multipleSupport ) {     
              fileArr = $file[0].files     
              for ( var i = 0, len = fileArr.length; i < len; i++ ) {     
                files.push( fileArr[i].name )     
              }     
              filename = files.join(', ')     
            // If not supported then just take the value     
            // and remove the path to just show the filename     
            } else {     
              filename = $file.val().split('\\').pop()     
            }     
            $input.val( filename ) // Set the value     
              .attr( 'title', filename ) // Show filename in title tootlip     
          })     
          $input.on({     
            focus: function () { $file.trigger('change') },     
            blur: function () { $file.trigger('blur') },     
            keydown: function( e ) {     
              if ( e.which === 13 ) { // Enter     
                if ( !isIE ) { $file.trigger('click') }     
              } else if ( e.which === 8 || e.which === 46 ) { // Backspace & Del     
                // On some browsers the value is read-only     
                // with this trick we remove the old input and add     
                // a clean clone with all the original events attached     
                $file.replaceWith( $file = $file.val('').clone( true ) )     
                $file.trigger('change')     
                $input.val('')     
              } else if ( e.which === 9 ){ // TAB     
                return     
              } else { // All other keys     
                return false     
              }     
            }     
          })     
        })     
      }     
    }( jQuery ))     
    /**    
     * @namespace Errors    
     * @locale en    
     */     
    $.idealforms.errors = {     
      required: '此處是必填的.',     
      number: '必須是數(shù)字.',     
      digits: '必須是唯一的數(shù)字.',     
      name: '必須至少有3個字符長,并且只能包含字母.',     
      username: '用戶名最短5位,最長30位,請使用英文字母、數(shù)字、中文和下劃線.用戶名首字符必須為字母、數(shù)字、中文,不能為全數(shù)字.中文最長21個字.',     
      pass: '密碼的位數(shù)必須的在6-15位之間,并且至少包含一個數(shù)字,一個大寫字母和一個小寫字母.',     
      strongpass: '必須至少為8個字符長,至少包含一個大寫字母和一個小寫字母和一個數(shù)字或特殊字符.',     
      email: '必須是一個有效的email地址. <em>(例: user@gmail.com)</em>',     
      phone: '必須是一個有效的手機號碼. <em>(例: 18723101212)</em>',     
      zip: 'Must be a valid US zip code. <em>(e.g. 33245 or 33245-0003)</em>',     
      url: 'Must be a valid URL. <em>(e.g. www.google.com)</em>',     
      minChar: 'Must be at least <strong>{0}</strong> characters long.',     
      minOption: 'Check at least <strong>{0}</strong> options.',     
      maxChar: 'No more than <strong>{0}</strong> characters long.',     
      maxOption: 'No more than <strong>{0}</strong> options allowed.',     
      range: 'Must be a number between {0} and {1}.',     
      date: 'Must be a valid date. <em>(e.g. {0})</em>',     
      dob: 'Must be a valid date of birth.',     
      exclude: '"{0}" is not available.',     
      excludeOption: '{0}',     
      equalto: 'Must be the same value as <strong>"{0}"</strong>',     
      extension: 'File(s) must have a valid extension. <em>(e.g. "{0}")</em>',     
      ajaxSuccess: '<strong>{0}</strong> is not available.',     
      ajaxError: 'Server error...'     
    }     
    /**    
     * Get all default filters    
     * @returns object    
     */     
    var getFilters = function() {     
      var filters = {     
        required: {     
          regex: /.+/,     
          error: $.idealforms.errors.required     
        },     
        number: {     
          regex: function( i, v ) { return !isNaN(v) },     
          error: $.idealforms.errors.number     
        },     
        digits: {     
          regex: /^\d+$/,     
          error: $.idealforms.errors.digits     
        },     
        name: {     
          regex: /^[A-Za-z]{3,}$/,     
          error: $.idealforms.errors.name     
        },     
        username: {     
          regex: /^[a-z](?=[\w.]{4,30}$)\w*\.?\w*$/i,     
          error: $.idealforms.errors.username     
        },     
        pass: {     
          regex: /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/,     
          error: $.idealforms.errors.pass     
        },     
        strongpass: {     
          regex: /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/,     
          error: $.idealforms.errors.strongpass     
        },     
        email: {     
          regex: /^([a-zA-Z0-9]*[-_.]?[a-zA-Z0-9]+)*@([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)+[\\.][A-Za-z]{2,3}([\\.][A-Za-z]{2})?$/,     
          error: $.idealforms.errors.email     
        },     
        phone: {     
          //regex: /^((13[0-9])|(15[0-9])|(17[0-9])|(18[0-9]))\\d{8}$/,     
          regex: /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/,     
          error: $.idealforms.errors.phone     
        },     
        zip: {     
          regex: /^\d{5}$|^\d{5}-\d{4}$/,     
          error: $.idealforms.errors.zip     
        },     
        url: {     
          regex: /^(?:(ftp|http|https):\/\/)?(?:[\w\-]+\.)+[a-z]{2,6}([\:\/?#].*)?$/i,     
          error: $.idealforms.errors.url     
        },     
        min: {     
          regex: function( input, value ) {     
            var $inputinput = input.input,     
                min = input.userOptions.data.min,     
                isRadioCheck = $input.is('[type="checkbox"], [type="radio"]')     
            if ( isRadioCheck ) {     
              this.error = $.idealforms.errors.minOption.replace( '{0}', min )     
              return $input.filter(':checked').length >= min     
            }     
            this.error = $.idealforms.errors.minChar.replace( '{0}', min )     
            return value.length >= min     
          }     
        },     
        max: {     
          regex: function( input, value ) {     
            var $inputinput = input.input,     
                max = input.userOptions.data.max,     
                isRadioCheck = $input.is('[type="checkbox"], [type="radio"]')     
            if ( isRadioCheck ) {     
              this.error = $.idealforms.errors.maxOption.replace( '{0}', max )     
              return $input.filter(':checked').length <= max     
            }     
            this.error = $.idealforms.errors.maxChar.replace( '{0}', max )     
            return value.length <= max     
          }     
        },     
        range: {     
          regex: function( input, value ) {     
            var range = input.userOptions.data.range,     
                val = +value     
            this.error = $.idealforms.errors.range     
              .replace( '{0}', range[0] )     
              .replace( '{1}', range[1] )     
            return val >= range[0] && val <= range[1]     
          }     
        },     
        date: {     
          regex: function( input, value ) {     
            var     
            userFormat =     
              input.userOptions.data && input.userOptions.data.date     
                ? input.userOptions.data.date     
                : 'mm/dd/yyyy', // default format     
            delimiter = /[^mdy]/.exec( userFormat )[0],     
            theFormat = userFormat.split(delimiter),     
            theDate = value.split(delimiter),     
            isDate = function( date, format ) {     
              var m, d, y     
              for ( var i = 0, len = format.length; i < len; i++ ) {     
                if ( /m/.test( format[i]) ) m = date[i]     
                if ( /d/.test( format[i]) ) d = date[i]     
                if ( /y/.test( format[i]) ) y = date[i]     
              }     
              return (     
                m > 0 && m < 13 &&     
                y && y.length === 4 &&     
                d > 0 && d <= ( new Date( y, m, 0 ) ).getDate()     
              )     
            }     
            this.error = $.idealforms.errors.date.replace( '{0}', userFormat )     
            return isDate( theDate, theFormat )     
          }     
        },     
        dob: {     
          regex: function( input, value ) {     
            var     
            userFormat =     
              input.userOptions.data && input.userOptions.data.dob     
                ? input.userOptions.data.dob     
                : 'mm/dd/yyyy', // default format     
            // Simulate a date input     
            dateInput = {     
              input: input.input,     
              userOptions: {     
                data: { date: userFormat }     
              }     
            },     
            // Use internal date filter to validate the date     
            isDate = filters.date.regex( dateInput, value ),     
            // DOB     
            theYear = /\d{4}/.exec( value ),     
            maxYear = new Date().getFullYear(), // Current year     
            minYear = maxYear - 100     
            this.error = $.idealforms.errors.dob     
            return isDate && theYear >= minYear && theYear <= maxYear     
          }     
        },     
        exclude: {     
          regex: function( input, value ) {     
            var $inputinput = input.input,     
                exclude = input.userOptions.data.exclude,     
                isOption = $input.is('[type="checkbox"], [type="radio"], select')     
            this.error = isOption     
              ? $.idealforms.errors.excludeOption.replace( '{0}', value )     
              : this.error = $.idealforms.errors.exclude.replace( '{0}', value )     
            return $.inArray( value, exclude ) === -1     
          }     
        },     
        equalto: {     
          regex: function( input, value ) {     
            var $equals = $( input.userOptions.data.equalto ),     
                $inputinput = input.input,     
                name = $equals.attr('name') || $equals.attr('id'),     
                isValid = $equals.parents('.ideal-field')     
                  .filter(function(){ return $(this).data('ideal-isvalid') === true })     
                  .length     
            if ( !isValid ) { return false }     
            this.error = $.idealforms.errors.equalto.replace( '{0}', name )     
            return $input.val() === $equals.val()     
          }     
        },     
        extension: {     
          regex: function( input, value ) {     
            var files = input.input[0].files || [{ name: value }],     
                extensions = input.userOptions.data.extension,     
                re = new RegExp( '\\.'+ extensions.join('|') +'$', 'i' ),     
                valid = false     
            for ( var i = 0, len = files.length; i < len; i++ ) {     
              valid = re.test( files[i].name );     
            }     
            this.error = $.idealforms.errors.extension.replace( '{0}', extensions.join('", "') )     
            return valid     
          }     
        },     
        ajax: {     
          regex: function( input, value, showOrHideError ) {     
            var self = this     
            var $inputinput = input.input     
            var userOptions = input.userOptions     
            var name = $input.attr('name')     
            var $field = $input.parents('.ideal-field')     
            var valid = false     
            var customErrors = userOptions.errors && userOptions.errors.ajax     
            self.error = {}     
            self.error.success = customErrors && customErrors.success     
              ? customErrors.success     
              : $.idealforms.errors.ajaxSuccess.replace( '{0}', value )     
            self.error.fail = customErrors && customErrors.error     
              ? customErrors.error     
              : $.idealforms.errors.ajaxError     
            // Send input name as $_POST[name]     
            var data = {}     
            data[ name ] = $.trim( value )     
            // Ajax options defined by the user     
            var userAjaxOps = input.userOptions.data.ajax     
            var ajaxOps = {     
              type: 'post',     
              dataType: 'json',     
              data: data,     
              success: function( resp, text, xhr ) {     
              console.log(resp)     
                showOrHideError( self.error.success, true )     
                $input.data({     
                  'ideal-ajax-resp': resp,     
                  'ideal-ajax-error': self.error.success     
                })     
                $input.trigger('change') // to update counter     
                $field.removeClass('ajax')     
                // Run custom success callback     
                if( userAjaxOps._success ) {     
                  userAjaxOps._success( resp, text, xhr )     
                }     
              },     
              error: function( xhr, text, error ) {     
                if ( text !== 'abort' ) {     
                  showOrHideError( self.error.fail, false )     
                  $input.data( 'ideal-ajax-error', self.error.fail )     
                  $field.removeClass('ajax')     
                  // Run custom error callback     
                  if ( userAjaxOps._error ) {     
                    userAjaxOps._error( xhr, text, error )     
                  }     
                }     
              }     
            }     
            $.extend( ajaxOps, userAjaxOps )     
            // Init     
            $input.removeData('ideal-ajax-error')     
            $input.removeData('ideal-ajax-resp')     
            $field.addClass('ajax')     
            // Run request and save it to be able to abort it     
            // so requests don't bubble     
            $.idealforms.ajaxRequests[ name ] = $.ajax( ajaxOps )     
          }     
        }     
      }     
      return filters     
    }     
    $.idealforms.flags = {     
      noerror: function (i) {     
        i.parent().siblings('.ideal-error').hide()     
      },     
      noicons: function (i) {     
        i.siblings('.ideal-icon-valid, .ideal-icon-invalid').hide()     
      },     
      novalidicon: function (i) {     
        i.siblings('.ideal-icon-valid').hide()     
      },     
      noinvalidicon: function (i) {     
        i.siblings('.ideal-icon-invalid').hide()     
      },     
      noclass: function (i) {     
        i.parents('.ideal-field').removeClass('valid invalid')     
      },     
      novalidclass: function (i) {     
        i.parents('.ideal-field').removeClass('valid')     
      },     
      noinvalidclass: function (i) {     
        i.parents('.ideal-field').removeClass('invalid')     
      }     
    }     
    /*    
     * Ideal Forms plugin    
     */     
    var _defaults = {     
      inputs: {},     
      customFilters: {},     
      customFlags: {},     
      globalFlags: '',     
      onSuccess: function(e) { alert('Thank you...') },     
      onFail: function() { alert('Invalid!') },     
      responsiveAt: 'auto',     
      disableCustom: ''     
    }     
    // Constructor     
    var IdealForms = function( element, options ) {     
      var self = this     
      self.$form = $( element )     
      self.opts = $.extend( {}, _defaults, options )     
      self.$tabs = self.$form.find('section')     
      // Set localized filters     
      $.extend( $.idealforms.filters, getFilters() )     
      self._init()     
    }     
    // Plugin     
    $.fn.idealforms = function( options ) {     
      return this.each(function() {     
        if ( !$.data( this, 'idealforms' ) ) {     
          $.data( this, 'idealforms', new IdealForms( this, options ) )     
        }     
      })     
    }     
    // Get LESS variables     
    var LessVars = {     
      fieldWidth: Utils.getLessVar( 'ideal-field-width', 'width' )     
    }     
    /*    
     * Private Methods    
     */     
    $.extend( IdealForms.prototype, {     
      _init: function() {     
        var self = this     
        var o = self.opts     
        var formElements = self._getFormElements()     
        self.$form.css( 'visibility', 'visible' )     
          .addClass('ideal-form')     
          .attr( 'novalidate', 'novalidate' ) // disable HTML5 validation     
        // Do markup     
        formElements.inputs     
          .add( formElements.headings )     
          .add( formElements.separators )     
          .each(function(){ self._doMarkup( $(this) ) })     
        // Generate tabs     
        if ( self.$tabs.length ) {     
          var $tabContainer = $('<div/>')     
          self.$form.prepend( $tabContainer )     
          self.$tabs.idealTabs( $tabContainer )     
        }     
        // Always show datepicker below the input     
        if ( jQuery.ui ) {     
          $.datepicker._checkOffset = function( a,b,c ) { return b }     
        }     
        // Add inputs specified by data-ideal     
        // to the list of user inputs     
        self.$form.find('[data-ideal]').each(function() {     
          var userInput = o.inputs[ this.name ]     
          o.inputs[ this.name ] = userInput || { filters: $(this).data('ideal') }     
        })     
       // Responsive     
        if ( o.responsiveAt ) {     
          $(window).resize(function(){ self._responsive() })     
          self._responsive()     
        }     
        // Form events     
        self.$form.on({     
          keydown: function( e ) {     
            // Prevent submit when pressing enter     
            // but exclude textareas     
            if ( e.which === 13 && e.target.nodeName !== 'TEXTAREA' ) {     
              e.preventDefault()     
            }     
          },     
          submit: function( e ) {     
            if ( !self.isValid() ) {     
              e.preventDefault()     
              o.onFail()     
              self.focusFirstInvalid()     
            } else {     
              o.onSuccess( e )     
            }     
          }     
        })     
        self._adjust()     
        self._attachEvents()     
        self.fresh() // Start fresh     
      },     
      _getFormElements: function() {     
        return {     
          inputs: this.$form.find('input, select, textarea, :button'),     
          labels: this.$form.find('div > label:first-child'),     
          text: this.$form.find('input:not([type="checkbox"], [type="radio"], [type="submit"]), textarea'),     
          select: this.$form.find('select'),     
          radiocheck: this.$form.find('input[type="radio"], input[type="checkbox"]'),     
          buttons: this.$form.find(':button'),     
          file: this.$form.find('input[type="file"]'),     
          headings: this.$form.find('h1, h2, h3, h4, h5, h6'),     
          separators: this.$form.find('hr'),     
          hidden: this.$form.find('input:hidden')     
        }     
      },     
      _getUserInputs: function() {     
        return this.$form.find('[name="'+ Utils.getKeys( this.opts.inputs ).join('"], [name="') +'"]')     
      },     
      _getTab: function( nameOrIdx ) {     
        var self = this     
        var isNumber = !isNaN( nameOrIdx )     
        if ( isNumber ) {     
          return self.$tabs.eq( nameOrIdx )     
        }     
        return self.$tabs.filter(function() {     
          var re = new RegExp( nameOrIdx, 'i' )     
          return re.test( $(this).data('ideal-tabs-content-name') )     
        })     
      },     
      _getCurrentTabIdx: function() {     
        return this.$tabs.index( this.$form.find('.ideal-tabs-content:visible') )     
      },     
      _updateTabsCounter: function() {     
        var self = this     
        self.$tabs.each(function( i ) {     
          var invalid = self.getInvalidInTab( i ).length     
          self.$tabs.updateCounter( i, invalid )     
        })     
      },     
      _adjust: function() {     
        var self = this     
        var o = self.opts     
        var formElements = self._getFormElements()     
        var curTab = self._getCurrentTabIdx()     
        // Autocomplete causes some problems...     
        formElements.inputs.attr('autocomplete', 'off')     
        // Show tabs to calculate dimensions     
        if ( self.$tabs.length ) { self.$tabs.show() }     
        // Adjust labels     
        var labels = formElements.labels     
        labels.removeAttr('style').width( Utils.getMaxWidth( labels ) )     
        // Adjust headings and separators     
        if ( self.$tabs.length ) {     
          this.$tabs.each(function(){     
            $( this ).find('.ideal-heading:first').addClass('first-child')     
          })     
        } else {     
          self.$form.find('.ideal-heading:first').addClass('first-child')     
        }     
        self._setDatepicker()     
        // Done calculating hide tabs     
        if ( self.$tabs.length ) {     
          self.$tabs.hide()     
          self.switchTab( curTab )     
        }     
      },     
      _setDatepicker: function() {     
        var o = this.opts     
        var $datepicker = this.$form.find('input.datepicker')     
        if ( jQuery.ui && $datepicker.length ) {     
          $datepicker.each(function() {     
            var userInput = o.inputs[ this.name ]     
            var data = userInput && userInput.data && userInput.data.date     
            var format = data ? data.replace( 'yyyy', 'yy' ) : 'mm/dd/yy'     
            $(this).datepicker({     
              dateFormat: format,     
              beforeShow: function( input ) {     
                $( input ).addClass('open')     
              },     
              onChangeMonthYear: function() {     
                // Hack to fix IE9 not resizing     
                var $this = $(this)     
                var w = $this.outerWidth() // cache first!     
                setTimeout(function() {     
                  $this.datepicker('widget').css( 'width', w )     
                }, 1)     
              },     
              onClose: function() { $(this).removeClass('open') }     
            })     
          })     
          // Adjust width     
          $datepicker.on('focus keyup', function() {     
            var t = $(this), w = t.outerWidth()     
            t.datepicker('widget').css( 'width', w )     
          })     
          $datepicker.parent().siblings('.ideal-error').addClass('hidden')     
        }     
      },     
      _doMarkup: function( $element ) {     
        var o = this.opts     
        var elementType = Utils.getIdealType( $element )     
        // Validation elements     
        var $field = $('<span/>')     
        var $error = $('<span />')     
        var $valid = $('<i />')     
        var $invalid = $('<i/>')     
          .click(function(){     
            $(this).parent().find('input:first, textarea, select').focus()     
          })     
        // Basic markup     
        $element.closest('div').addClass('ideal-wrap')     
          .children('label:first-child').addClass('ideal-label')     
        var idealElements = {     
          _defaultInput: function() {     
            $element.wrapAll( $field ).after( $valid, $invalid )     
              .parent().after( $error )     
          },     
          text: function() { idealElements._defaultInput() },     
          radiocheck: function() {     
            // Check if input is already wrapped so we don't     
            // wrap radios and checks more than once     
            var isWrapped = $element.parents('.ideal-field').length     
            if ( !isWrapped ) {     
              $element.parent().nextAll().andSelf().wrapAll( $field.addClass('ideal-radiocheck') )     
              $element.parents('.ideal-field').append( $valid, $invalid ).after( $error )     
            }     
            if ( !/radiocheck/.test( o.disableCustom ) ) {     
              $element.idealRadioCheck()     
            }     
          },     
          select: function() {     
            idealElements._defaultInput()     
            if ( !/select/.test( o.disableCustom ) ) {     
              $element.idealSelect()     
            }     
          },     
          file: function() {     
            idealElements._defaultInput()     
            if ( !/file/.test( o.disableCustom ) ) {     
              $element.idealFile()     
            }     
          },     
          button: function() {     
            if ( !/button/.test( o.disableCustom ) ) {     
              $element.addClass('ideal-button')     
            }     
          },     
          hidden: function() {     
            $element.closest('div').addClass('ideal-hidden')     
          },     
          heading: function() {     
            $element.closest('div').addClass('ideal-full-width')     
            $element.parent().children().wrapAll('<span/>')     
          },     
          separator: function() {     
            $element.closest('div').addClass('ideal-full-width')     
            $element.wrapAll('<div/>')     
          }     
        }     
        // Generate markup for current element type     
        idealElements[ elementType ] ? idealElements[ elementType ]() : $.noop()     
        $error.add( $valid ).add( $invalid ).hide() // Start fresh     
      },     
      /** Validates an input and shows or hides error and icon    
       * @memberOf Actions    
       * @param {object} $input jQuery object    
       * @param {string} e The JavaScript event    
       */     
      _validate: function( $input, e ) {     
        var self = this     
        var o = this.opts     
        var userOptions = o.inputs[ $input.attr('name') ]     
        var userFilters = userOptions.filters && userOptions.filters.split(/\s/)     
        var name = $input.attr('name')     
        var value = $input.val()     
        var ajaxRequest = $.idealforms.ajaxRequests[ name ]     
        var isRadioCheck = $input.is('[type="checkbox"], [type="radio"]')     
        var inputData = {     
          // If is radio or check validate all inputs related by name     
          input: isRadioCheck ? self.$form.find('[name="' + name + '"]') : $input,     
          userOptions: userOptions     
        }     
        // Validation elements     
        var $field = $input.parents('.ideal-field')     
        var $error = $field.siblings('.ideal-error')     
        var $invalid = isRadioCheck     
          ? $input.parent().siblings('.ideal-icon-invalid')     
          : $input.siblings('.ideal-icon-invalid')     
        var $valid = isRadioCheck     
          ? $input.parent().siblings('.ideal-icon-valid')     
          : $input.siblings('.ideal-icon-valid')     
        function resetError() {     
          $field.removeClass('valid invalid').removeData('ideal-isvalid')     
          $error.add( $invalid ).add( $valid ).hide()     
        }     
        function showOrHideError( error, valid ) {     
          resetError()     
          valid ? $valid.show() : $invalid.show()     
          $field.addClass( valid ? 'valid' : 'invalid' )     
          $field.data( 'ideal-isvalid', valid )     
          if ( !valid ) {     
            $error.html( error ).toggle( $field.is('.ideal-field-focus') )     
          }     
        }     
        // Prevent validation when typing but not introducing any new characters     
        // This is mainly to prevent multiple AJAX requests     
        var oldValue = $input.data('ideal-value') || 0     
        $input.data( 'ideal-value', value )     
        if ( e.type === 'keyup' && value === oldValue ) { return false }     
        // Validate     
        if ( userFilters ) {     
          $.each( userFilters, function( i, filter ) {     
            var theFilter = $.idealforms.filters[ filter ]     
            var customError = userOptions.errors && userOptions.errors[ filter ]     
            var error = ''     
            // If field is empty and not required     
            if ( !value && filter !== 'required' ) {     
              resetError()     
              return false     
            }     
            if ( theFilter ) {     
              // Abort and reset ajax if there's a request pending     
              if ( e.type === 'keyup' && ajaxRequest ) {     
                ajaxRequest.abort()     
                $field.removeClass('ajax')     
              }     
              // AJAX     
              if ( filter === 'ajax' ) {     
                showOrHideError( error, false ) // set invalid till response comes back     
                $error.hide()     
                if ( e.type === 'keyup' ) {     
                  theFilter.regex( inputData, value, showOrHideError ) // runs the ajax callback     
                } else {     
                  var ajaxError = $input.data('ideal-ajax-error')     
                  if ( ajaxError ) {     
                    showOrHideError( ajaxError, $input.data('ideal-ajax-resp') || false )     
                  }     
                }     
              }     
              // All other filters     
              else {     
                var valid = Utils.isRegex( theFilter.regex ) && theFilter.regex.test( value ) ||     
                            Utils.isFunction( theFilter.regex ) && theFilter.regex( inputData, value )     
                error = customError || theFilter.error // assign error after calling regex()     
                showOrHideError( error, valid )     
                if ( !valid ) { return false }     
              }     
            }     
          })     
        }     
        // Reset if there are no filters     
        else {     
          resetError()     
        }     
        // Flags     
        var flags = (function(){     
          var f = userOptions.flags && userOptions.flags.split(' ') || []     
          if ( o.globalFlags ) {     
            $.each( o.globalFlags.split(' '), function( i,v ) { f.push(v) })     
          }     
          return f     
        }())     
        if ( flags.length ) {     
          $.each(flags, function( i,f ) {     
            var theFlag = $.idealforms.flags[f]     
            if ( theFlag ) { theFlag( $input, e.type ) }     
          })     
        }     
        // Update counter     
        if ( self.$tabs.length ) {     
          self._updateTabsCounter( self._getCurrentTabIdx() )     
        }     
      },     
      _attachEvents: function() {     
        var self = this     
        self._getUserInputs().on('keyup change focus blur', function(e) {     
          var $this = $(this)     
          var $field = $this.parents('.ideal-field')     
          var isFile = $this.is('input[type=file]')     
          // Trigger on change if type=file cuz custom file     
          // disables focus on original file input (tabIndex = -1)     
          if ( e.type === 'focus' || isFile && e.type === 'change' ) {     
            $field.addClass('ideal-field-focus')     
          }     
          if ( e.type === 'blur' ) {     
            $field.removeClass('ideal-field-focus')     
          }     
          self._validate( $this, e )     
        })     
      },     
      _responsive: function() {     
        var formElements = this._getFormElements()     
        var maxWidth = LessVars.fieldWidth + formElements.labels.outerWidth()     
        var $emptyLabel = formElements.labels.filter(function() {     
          return $(this).html() === ' '     
        })     
        var $customSelect = this.$form.find('.ideal-select')     
        this.opts.responsiveAt === 'auto'     
          ? this.$form.toggleClass( 'stack', this.$form.width() < maxWidth )     
          : this.$form.toggleClass( 'stack', $(window).width() < this.opts.responsiveAt )     
        var isStack = this.$form.is('.stack')     
        $emptyLabel.toggle( !isStack )     
        $customSelect.trigger( isStack ? 'list' : 'menu' )     
        // Hide datePicker     
        var $datePicker = this.$form.find('input.hasDatepicker')     
        if ( $datePicker.length ) { $datePicker.datepicker('hide') }     
      }     
    })     
    /*    
     * Public Methods    
     */     
    $.extend( IdealForms.prototype, {     
      getInvalid: function() {     
        return this.$form.find('.ideal-field').filter(function() {     
          return $(this).data('ideal-isvalid') === false     
        })     
      },     
      getInvalidInTab: function( nameOrIdx ) {     
        return this._getTab( nameOrIdx ).find('.ideal-field').filter(function() {     
          return $(this).data('ideal-isvalid') === false     
        })     
      },     
      isValid: function() {     
        return !this.getInvalid().length     
      },     
      isValidField: function( field ) {     
        var $input = Utils.getByNameOrId( field )     
        return $input.parents('.ideal-field').data('ideal-isvalid') === true     
      },     
      focusFirst: function() {     
        if ( this.$tabs.length ) {     
          this.$tabs.filter(':visible')     
            .find('.ideal-field:first')     
            .find('input:first, select, textarea').focus()     
        } else {     
          this.$form.find('.ideal-field:first')     
            .find('input:first, select, textarea').focus()     
        }     
        return this     
      },     
      focusFirstInvalid: function() {     
        var $first = this.getInvalid().first().find('input:first, select, textarea')     
        var tabName = $first.parents('.ideal-tabs-content').data('ideal-tabs-content-name')     
        if ( this.$tabs.length ) {     
          this.switchTab( tabName )     
        }     
        $first.focus()     
        return this     
      },     
      switchTab: function( nameOrIdx ) {     
        this.$tabs.switchTab( nameOrIdx )     
        return this     
      },     
      nextTab: function() {     
        this.$tabs.nextTab()     
        return this     
      },     
      prevTab: function() {     
        this.$tabs.prevTab()     
        return this     
      },     
      firstTab: function() {     
        this.$tabs.firstTab()     
        return this     
      },     
      lastTab: function() {     
        this.$tabs.lastTab()     
        return this     
      },     
      fresh: function() {     
        this._getUserInputs().change().parents('.ideal-field')     
          .removeClass('valid invalid')     
        return this     
      },     
      freshFields: function( fields ) {     
        fields = Utils.convertToArray( fields )     
        $.each( fields, function( i ) {     
          var $input = Utils.getByNameOrId( fields[ i ] )     
          $input.change().parents('.ideal-field').removeClass('valid invalid')     
        })     
        return this     
      },     
      reload: function() {     
        this._adjust()     
        this._attachEvents()     
        return this     
      },     
      reset: function() {     
        var formElements = this._getFormElements()     
        formElements.text.val('') // text inputs     
        formElements.radiocheck.removeAttr('checked') // radio & check     
        // Select and custom select     
        formElements.select.find('option').first().prop( 'selected', true )     
        this.$form.find('.ideal-select').trigger('reset')     
        if ( this.$tabs.length ) { this.firstTab() }     
        this.focusFirst().fresh()     
        return this     
      },     
      resetFields: function( fields ) {     
        fields = Utils.convertToArray( fields )     
        var formElements = this._getFormElements()     
        $.each( fields, function( i, v ) {     
          var $input = Utils.getByNameOrId( v )     
          var type = Utils.getIdealType( $input )     
          if ( type === 'text' || type === 'file' ) {     
            $input.val('')     
          }     
          if ( type === 'radiocheck' ) {     
            $input.removeAttr('checked') // radio & check     
          }     
          if ( type === 'select' ) {     
            $input.find('option').first().prop( 'selected', true )     
            $input.next('.ideal-select').trigger('reset')     
          }     
          $input.change()     
        })     
        this.freshFields( fields )     
        return this     
      },     
      toggleFields: function( fields ) {     
        fields = Utils.convertToArray( fields )     
        var self = this     
        var $fields = Utils.getFieldsFromArray( fields )     
        $fields.each(function() {     
          var $this = $(this)     
          var name = $this.attr('name') || $this.attr('id')     
          var input = self.opts.inputs[ name ]     
          var filters = input && input.filters     
          var dataFilters = $this.data('ideal-filters') || ''     
          $this.data( 'ideal-filters', filters )     
          $this.closest('.ideal-wrap').toggle()     
          self.setFieldOptions( name, { filters: dataFilters } )     
        })     
        return this     
      },     
      setOptions: function( options ) {     
        $.extend( true, this.opts, options )     
        this.reload().fresh()     
        return this     
      },     
      setFieldOptions: function( name, options ) {     
        $.extend( true, this.opts.inputs[ name ], options )     
        this.reload().freshFields([ name ])     
        return this     
      },     
      addFields: function( fields ) {     
        fields = Utils.convertToArray( fields )     
        var self = this     
        // Save names of all inputs in Array     
        // to use methods that take names ie. fresh()     
        var allNames = []     
        // Add an input to the DOM     
        function add( ops ) {     
          var name = ops.name     
          var userOptions = {     
            filters: ops.filters || '',     
            data: ops.data || {},     
            errors: ops.errors || {},     
            flags: ops.flags || ''     
          }     
          var label = ops.label || ''     
          var type = ops.type     
          var list = ops.list || []     
          var placeholder = ops.placeholder || ''     
          var value = ops.value || ''     
          var $field = $('<div>'+     
              '<label>'+ label +':</label>'+     
              Utils.makeInput( name, value, type, list, placeholder ) +     
            '</div>')     
          var $input = $field.find('input, select, textarea, :button')     
          // Add inputs with filters to the list     
          // of user inputs to validate     
          if ( userOptions.filters ) { self.opts.inputs[ name ] = userOptions }     
          self._doMarkup( $input )     
          // Insert in DOM     
          if ( ops.addAfter ) {     
            $field.insertAfter(     
              $( Utils.getByNameOrId( ops.addAfter ) ).parents('.ideal-wrap')     
            )     
          } else if ( ops.addBefore ) {     
            $field.insertBefore(     
              $(Utils.getByNameOrId( ops.addBefore ))     
              .parents('.ideal-wrap')     
            )     
          } else if ( ops.appendToTab ) {     
            $field.insertAfter(     
              self._getTab( ops.appendToTab ).find('.ideal-wrap:last-child')     
            )     
          } else {     
            $field.insertAfter( self.$form.find('.ideal-wrap').last() )     
          }     
          // Add current field name to list of names     
          allNames.push( name )     
        }     
        // Run through each input     
        $.each( fields, function( i, ops ) { add( ops ) })     
        self.reload()     
        self.freshFields( allNames )     
        self._responsive()     
        return this     
      },     
      removeFields: function( fields ) {     
        fields = Utils.convertToArray( fields )     
        var $fields = Utils.getFieldsFromArray( fields )     
        $fields.parents('.ideal-wrap').remove()     
        this.reload()     
        return this     
      }     
    })     
    }( jQuery, window, document ))    
    以上所述是本文的全部內(nèi)容希望對大家有所幫助!