


Html5 implements user registration automatic verification function example code
抽时间写了一个带有自动校验功能的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) --> <p class="main" > <p style="height:5px;text-align:center;font-size:25px"> 欢迎您注册!</p> <!-- Begin Form --> <form id="my-form" class="myform"> <p> <label>用户名:</label><input id="username" name="username" type="text" /> </p> <p> <!-- <label>密码:</label><input id="pass" name="password" type="password" /> --> <label>密码:</label><input id="pass" name="password" type="text" /> </p> <p> <label>邮箱:</label><input id="email" name="email" data-ideal="required email" type="email" /> </p> <p> <label>电话:</label><input id="telephone" type="text" name="phone" data-ideal="phone" /> </p> <p> <label>供应商V码:</label><input id="vCode" type="text" name="vCode" data-ideal="vCode" /> </p> <p> <label>真实姓名:</label><input id="trueName" type="text" name="trueName" data-ideal="trueName" /> </p> <p> <label>手机验证码:</label><input id="telCode" type="text" name="telCode" data-ideal="telCode" /> </p> <p 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;" /> </p> <!--<p> <label>性别:</label> <select id="sex" name="sex"> <option value="男">男</option> <option value="女">女</option> </select> </p> <p> <label>昵称:</label><input id="nickName" type="text" name="nickName" data-ideal="nickName" /> </p> <p> <label>年龄:</label><input id="age" type="text" name="age" data-ideal="age" /> </p>--> <!-- <p> <label>地址:</label><input type="text" name="address" data-ideal="address" /> </p> <p> <label>QQ:</label><input type="text" name="qq" data-ideal="qq" /> </p> <p> <label>邮编:</label><input type="text" name="zip" data-ideal="zip" /> </p> <p> <label>传真:</label><input type="text" name="fax" data-ideal="fax" /> </p> <p> <label>身份证:</label><input type="text" name="creditID" data-ideal="creditID" /> </p> <p> <label>出生日期:</label><input name="date" class="datepicker" data-ideal="date" type="text" placeholder="月/日/年" /> </p> <p> <label>上传头像:</label><input id="file" name="file" multiple type="file" /> </p> <p> <label>个人主页:</label><input name="website" data-ideal="url" type="text" /> </p> <p> <label>备注:</label> <textarea id="comments" name="comments"></textarea> </p> --> <!-- <p 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> </p> <p> <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> </p> <p> <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> </p> --> <p style="margin-top:10px; margin-left:100px;margin-right:100px;"> <button type="button" id="submit" class="submit">提交</button> <button id="reset" type="button" >重置</button> </p> </form> <!-- End Form --> </p> <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://www.php.cn/: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://www.php.cn/: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地址. (例: user@gmail.com)'
phone: '必须是一个有效的手机号码. (例: 18723101212)'
以下是整个代码文件:
/*-------------------------------------------------------------------------- jq-idealforms 2.1 * Author: Cedric Ruiz * License: GPL or MIT * Demo: http://www.php.cn/ * --------------------------------------------------------------------------*/ ;(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, $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 = $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 = $('<p 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 $inputinput = input.input, min = input.userOptions.data.min, isRadioCheck = $input.is('[type="checkbox"], [type="radio"]') if ( isRadioCheck ) { this.error = $.idealforms.errors.minOption.replace( '{0}', min ) return $input.filter(':checked').length >= min } this.error = $.idealforms.errors.minChar.replace( '{0}', min ) return value.length >= min } }, max: { regex: function( input, value ) { var $inputinput = input.input, max = input.userOptions.data.max, isRadioCheck = $input.is('[type="checkbox"], [type="radio"]') if ( isRadioCheck ) { this.error = $.idealforms.errors.maxOption.replace( '{0}', max ) return $input.filter(':checked').length <= max } this.error = $.idealforms.errors.maxChar.replace( '{0}', max ) return value.length <= max } }, range: { regex: function( input, value ) { var range = input.userOptions.data.range, val = +value this.error = $.idealforms.errors.range .replace( '{0}', range[0] ) .replace( '{1}', range[1] ) return val >= range[0] && val <= range[1] } }, date: { regex: function( input, value ) { var userFormat = input.userOptions.data && input.userOptions.data.date ? input.userOptions.data.date : 'mm/dd/yyyy', // default format delimiter = /[^mdy]/.exec( userFormat )[0], theFormat = userFormat.split(delimiter), theDate = value.split(delimiter), isDate = function( date, format ) { var m, d, y for ( var i = 0, len = format.length; i < len; i++ ) { if ( /m/.test( format[i]) ) m = date[i] if ( /d/.test( format[i]) ) d = date[i] if ( /y/.test( format[i]) ) y = date[i] } return ( m > 0 && m < 13 && y && y.length === 4 && d > 0 && d <= ( new Date( y, m, 0 ) ).getDate() ) } this.error = $.idealforms.errors.date.replace( '{0}', userFormat ) return isDate( theDate, theFormat ) } }, dob: { regex: function( input, value ) { var userFormat = input.userOptions.data && input.userOptions.data.dob ? input.userOptions.data.dob : 'mm/dd/yyyy', // default format // Simulate a date input dateInput = { input: input.input, userOptions: { data: { date: userFormat } } }, // Use internal date filter to validate the date isDate = filters.date.regex( dateInput, value ), // DOB theYear = /\d{4}/.exec( value ), maxYear = new Date().getFullYear(), // Current year minYear = maxYear - 100 this.error = $.idealforms.errors.dob return isDate && theYear >= minYear && theYear <= maxYear } }, exclude: { regex: function( input, value ) { var $inputinput = input.input, exclude = input.userOptions.data.exclude, isOption = $input.is('[type="checkbox"], [type="radio"], select') this.error = isOption ? $.idealforms.errors.excludeOption.replace( '{0}', value ) : this.error = $.idealforms.errors.exclude.replace( '{0}', value ) return $.inArray( value, exclude ) === -1 } }, equalto: { regex: function( input, value ) { var $equals = $( input.userOptions.data.equalto ), $inputinput = input.input, name = $equals.attr('name') || $equals.attr('id'), isValid = $equals.parents('.ideal-field') .filter(function(){ return $(this).data('ideal-isvalid') === true }) .length if ( !isValid ) { return false } this.error = $.idealforms.errors.equalto.replace( '{0}', name ) return $input.val() === $equals.val() } }, extension: { regex: function( input, value ) { var files = input.input[0].files || [{ name: value }], extensions = input.userOptions.data.extension, re = new RegExp( '\\.'+ extensions.join('|') +'$', 'i' ), valid = false for ( var i = 0, len = files.length; i < len; i++ ) { valid = re.test( files[i].name ); } this.error = $.idealforms.errors.extension.replace( '{0}', extensions.join('", "') ) return valid } }, ajax: { regex: function( input, value, showOrHideError ) { var self = this var $inputinput = input.input var userOptions = input.userOptions var name = $input.attr('name') var $field = $input.parents('.ideal-field') var valid = false var customErrors = userOptions.errors && userOptions.errors.ajax self.error = {} self.error.success = customErrors && customErrors.success ? customErrors.success : $.idealforms.errors.ajaxSuccess.replace( '{0}', value ) self.error.fail = customErrors && customErrors.error ? customErrors.error : $.idealforms.errors.ajaxError // Send input name as $_POST[name] var data = {} data[ name ] = $.trim( value ) // Ajax options defined by the user var userAjaxOps = input.userOptions.data.ajax var ajaxOps = { type: 'post', dataType: 'json', data: data, success: function( resp, text, xhr ) { console.log(resp) showOrHideError( self.error.success, true ) $input.data({ 'ideal-ajax-resp': resp, 'ideal-ajax-error': self.error.success }) $input.trigger('change') // to update counter $field.removeClass('ajax') // Run custom success callback if( userAjaxOps._success ) { userAjaxOps._success( resp, text, xhr ) } }, error: function( xhr, text, error ) { if ( text !== 'abort' ) { showOrHideError( self.error.fail, false ) $input.data( 'ideal-ajax-error', self.error.fail ) $field.removeClass('ajax') // Run custom error callback if ( userAjaxOps._error ) { userAjaxOps._error( xhr, text, error ) } } } } $.extend( ajaxOps, userAjaxOps ) // Init $input.removeData('ideal-ajax-error') $input.removeData('ideal-ajax-resp') $field.addClass('ajax') // Run request and save it to be able to abort it // so requests don't bubble $.idealforms.ajaxRequests[ name ] = $.ajax( ajaxOps ) } } } return filters } $.idealforms.flags = { noerror: function (i) { i.parent().siblings('.ideal-error').hide() }, noicons: function (i) { i.siblings('.ideal-icon-valid, .ideal-icon-invalid').hide() }, novalidicon: function (i) { i.siblings('.ideal-icon-valid').hide() }, noinvalidicon: function (i) { i.siblings('.ideal-icon-invalid').hide() }, noclass: function (i) { i.parents('.ideal-field').removeClass('valid invalid') }, novalidclass: function (i) { i.parents('.ideal-field').removeClass('valid') }, noinvalidclass: function (i) { i.parents('.ideal-field').removeClass('invalid') } } /* * Ideal Forms plugin */ var _defaults = { inputs: {}, customFilters: {}, customFlags: {}, globalFlags: '', onSuccess: function(e) { alert('Thank you...') }, onFail: function() { alert('Invalid!') }, responsiveAt: 'auto', disableCustom: '' } // Constructor var IdealForms = function( element, options ) { var self = this self.$form = $( element ) self.opts = $.extend( {}, _defaults, options ) self.$tabs = self.$form.find('section') // Set localized filters $.extend( $.idealforms.filters, getFilters() ) self._init() } // Plugin $.fn.idealforms = function( options ) { return this.each(function() { if ( !$.data( this, 'idealforms' ) ) { $.data( this, 'idealforms', new IdealForms( this, options ) ) } }) } // Get LESS variables var LessVars = { fieldWidth: Utils.getLessVar( 'ideal-field-width', 'width' ) } /* * Private Methods */ $.extend( IdealForms.prototype, { _init: function() { var self = this var o = self.opts var formElements = self._getFormElements() self.$form.css( 'visibility', 'visible' ) .addClass('ideal-form') .attr( 'novalidate', 'novalidate' ) // disable HTML5 validation // Do markup formElements.inputs .add( formElements.headings ) .add( formElements.separators ) .each(function(){ self._doMarkup( $(this) ) }) // Generate tabs if ( self.$tabs.length ) { var $tabContainer = $('<p 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('p > 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('p').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('p').addClass('ideal-hidden') }, heading: function() { $element.closest('p').addClass('ideal-full-width') $element.parent().children().wrapAll('<span class="ideal-heading"/>') }, separator: function() { $element.closest('p').addClass('ideal-full-width') $element.wrapAll('<p 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 = $('<p>'+ '<label>'+ label +':</label>'+ Utils.makeInput( name, value, type, list, placeholder ) + '</p>') 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 ))
以上就是Html5实现用户注册自动校验功能实例代码 的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











Guide to Table Border in HTML. Here we discuss multiple ways for defining table-border with examples of the Table Border in HTML.

This is a guide to Nested Table in HTML. Here we discuss how to create a table within the table along with the respective examples.

Guide to HTML margin-left. Here we discuss a brief overview on HTML margin-left and its Examples along with its Code Implementation.

There are various reasons for being unable to register for the BitgetWallet exchange, including account restrictions, unsupported regions, network issues, system maintenance and technical failures. To register for the BitgetWallet exchange, please visit the official website, fill in the information, agree to the terms, complete registration and verify your identity.

Guide to HTML Table Layout. Here we discuss the Values of HTML Table Layout along with the examples and outputs n detail.

Guide to HTML Input Placeholder. Here we discuss the Examples of HTML Input Placeholder along with the codes and outputs.

Guide to HTML onclick Button. Here we discuss their introduction, working, examples and onclick Event in various events respectively.

HTML5 Interview Questions 1. What are HTML5 multimedia elements 2. What is canvas element 3. What is geolocation API 4. What are Web Workers
