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

1.页面代码:usersRegister.hbs
- <!DOCTYPE html> 
- <!--[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> 
- nbsp; <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>(例: 该邮件地址已受到反垃圾邮件插件保护。要显示它需要在浏览器中启用 JavaScript。)</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 === nbsp;'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 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&nbnbsp;= $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 { 
- &nnbsp;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>(例: 该邮件地址已受到反垃圾邮件插件保护。要显示它需要在浏览器中启用 JavaScript。)</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 ) { 
- nbsp;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 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( nbsp;$(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' ) { 
- nbsp; 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 
-  nbsp; 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 )) 
【相关推荐】
1. Html5免费视频教程
以上就是H5完成用户注册自动校验的实例详解的知识。速戳>>知识兔学习精品课!
