Html5用户注册自动校验

来源:互联网 发布:linux打开设置界面 编辑:程序博客网 时间:2024/06/11 03:50

        抽时间写了一个带有自动校验功能的Html5用户注册Demo。使用到Handlebars模板技术和手机验证码校验。

     以下是效果截图:

       

    1.页面代码:usersRegister.hbs

<!DOCTYPE html><!--[if IE 8 ]> <html lang="en" class="ie8"> <![endif]--><!--[if IE 9 ]> <html lang="en" class="ie9"> <![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><!-- style="background-image: url(static/image/bg.jpg) -->    <div class="main" >        <div style="height:5px;text-align:center;font-size:25px"> 欢迎您注册!</div>        <!-- Begin Form -->        <form id="my-form" class="myform">            <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>供应商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 style="margin-bottom:5px;">                <button id="getTelCode" type="button" style="margin-left:160px; margin-right:auto;" >获取手机校验码</button>                <hr style="margin-top:5px; margin-bottom:5px;" />            </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" class="datepicker"                    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 style="margin-top:10px; margin-left:100px;margin-right:100px;">                <button type="button" id="submit" class="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) {               //获取当前网址,如: 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,我略有修改。

  部分校验的规则如下: 

  required: '此处是必填的.',  number: '必须是数字.',  digits: '必须是唯一的数字.',  name: '必须至少有3个字符长,并且只能包含字母.',  username: '用户名最短5,最长30,请使用英文字母、数字、中文和下划线. 用户名首字符必须为字母、数字、中文,不能为全数字.中文最长21个字.',  pass: '密码的位数必须的在6-15位之间,并且至少包含一个数字,一个大写字母和一个小写字母.',  strongpass: '必须至少为8个字符长,至少包含一个大写字母和一个小写字母和一个数字或特殊字符.',  email: '必须是一个有效的email地址. <em>(: user@gmail.com)</em>',  phone: '必须是一个有效的手机号码. <em>(: 18723101212)</em>'
  以下是整个代码文件:

/*--------------------------------------------------------------------------  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 class="' + name + '"></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,  $container = container,  $wrapper = $('<ul class="ideal-tabs-wrap"/>'),  $tabs = (function () {    var tabs = []    $contents.each(function () {      var name = $(this).attr('name')      var html =        '<li class="ideal-tabs-tab">'+          '<span>' + name + '</span>'+          '<i class="ideal-tabs-tab-counter ideal-tabs-tab-counter-zero">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 class="ideal-select '+ $select.attr('name') +'"/>'),      $menu = $(        '<li><span class="ideal-select-title">' +          $options.filter(':selected').text() +        '</span></li>'      ),      items = (function () {        var items = []        $options.each(function () {          var $this = $(this)          items.push('<li class="ideal-select-item">' + $this.text() + '</li>')        })        return items      }())      $menu.append('<ul class="ideal-select-sub">' + 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 class="ideal-file-wrap">'),          $input = $('<input type="text" class="ideal-file-filename" />'),          // Button that will be used in non-IE browsers          $button = $('<button type="button" class="ideal-file-upload">Open</button>'),          // Hack for IE          $label = $('<label class="ideal-file-upload" 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: '必须是数字.',  digits: '必须是唯一的数字.',  name: '必须至少有3个字符长,并且只能包含字母.',  username: '用户名最短5位,最长30位,请使用英文字母、数字、中文和下划线.用户名首字符必须为字母、数字、中文,不能为全数字.中文最长21个字.',  pass: '密码的位数必须的在6-15位之间,并且至少包含一个数字,一个大写字母和一个小写字母.',  strongpass: '必须至少为8个字符长,至少包含一个大写字母和一个小写字母和一个数字或特殊字符.',  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 $input = 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 $input = 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 $input = 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 ),            $input = 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 $input = 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: ''}// Constructorvar 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 variablesvar 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 class="ideal-wrap ideal-tabs ideal-full-width"/>')      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 class="ideal-field"/>')    var $error = $('<span class="ideal-error" />')    var $valid = $('<i class="ideal-icon ideal-icon-valid" />')    var $invalid = $('<i class="ideal-icon ideal-icon-invalid"/>')      .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 class="ideal-heading"/>')      },      separator: function() {        $element.closest('div').addClass('ideal-full-width')        $element.wrapAll('<div class="ideal-separator"/>')      }    }    // 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 ))

2 0
原创粉丝点击