


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)!

The H5 tag in HTML is a fifth-level title that is used to tag smaller titles or sub-titles. 1) The H5 tag helps refine content hierarchy and improve readability and SEO. 2) Combined with CSS, you can customize the style to enhance the visual effect. 3) Use H5 tags reasonably to avoid abuse and ensure the logical content structure.

The methods of building a website in HTML5 include: 1. Use semantic tags to define the web page structure, such as, , etc.; 2. Embed multimedia content, use and tags; 3. Apply advanced functions such as form verification and local storage. Through these steps, you can create a modern web page with clear structure and rich features.

A reasonable H5 code structure allows the page to stand out among a lot of content. 1) Use semantic labels such as, etc. to organize content to make the structure clear. 2) Control the rendering effect of pages on different devices through CSS layout such as Flexbox or Grid. 3) Implement responsive design to ensure that the page adapts to different screen sizes.

The main differences between HTML5 (H5) and older versions of HTML include: 1) H5 introduces semantic tags, 2) supports multimedia content, and 3) provides offline storage functions. H5 enhances the functionality and expressiveness of web pages through new tags and APIs, such as and tags, improving user experience and SEO effects, but need to pay attention to compatibility issues.

The difference between H5 and HTML5 is: 1) HTML5 is a web page standard that defines structure and content; 2) H5 is a mobile web application based on HTML5, suitable for rapid development and marketing.

The core features of HTML5 include semantic tags, multimedia support, form enhancement, offline storage and local storage. 1. Semantic tags such as, improve code readability and SEO effect. 2. Multimedia support simplifies the process of embedding media content through and tags. 3. Form Enhancement introduces new input types and verification properties, simplifying form development. 4. Offline storage and local storage improve web page performance and user experience through ApplicationCache and localStorage.

HTML5isamajorrevisionoftheHTMLstandardthatrevolutionizeswebdevelopmentbyintroducingnewsemanticelementsandcapabilities.1)ItenhancescodereadabilityandSEOwithelementslike,,,and.2)HTML5enablesricher,interactiveexperienceswithoutplugins,allowingdirectembe

Advanced tips for H5 include: 1. Use complex graphics to draw, 2. Use WebWorkers to improve performance, 3. Enhance user experience through WebStorage, 4. Implement responsive design, 5. Use WebRTC to achieve real-time communication, 6. Perform performance optimization and best practices. These tips help developers build more dynamic, interactive and efficient web applications.


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

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

EditPlus Chinese cracked version
Small size, syntax highlighting, does not support code prompt function

DVWA
Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software
