欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  web前端

H5完成用户注册自动校验的实例详解

程序员文章站 2022-03-11 09:53:52
...

Html5实现用户注册自动校验功能实例代码

05-24 10:49:46作者:

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

以下是效果截图:

H5完成用户注册自动校验的实例详解

1.页面代码:usersRegister.hbs

XML/HTML Code复制内容到剪贴板
  1. <!DOCTYPE html>

  2. <!--[if IE 8 ]> <html lang="en" class="ie8"> <![endif]-->

  3. <!--[if IE 9 ]> <html lang="en" class="ie9"> <![endif]-->

  4. <!--[if (gt IE 9)|!(IE)]><!-->

  5. <html lang="en">

  6. <!--<![endif]-->

  7. <head>

  8. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

  9. <meta http-equiv="X-UA-Compatible" content="IE=edge" />

  10. <title>用户注册</title>

  11. <!--[if lt IE 9]>

  12. <script src="/assets/scripts/html5shiv.js"></script>

  13. <![endif]-->

  14. <link href="/assets/styles/jquery.idealforms.min.css" rel="stylesheet" media="screen" />

  15. <style type="text/css">

  16. body {

  17. font: normal 15px/1.5 Arial, Helvetica, Free Sans, sans-serif;

  18. color: #222;

  19. overflow-y: scroll;

  20. padding: 60px 0 0 0;

  21. }

  22. .main {

  23. width: 560px;

  24. height: 480px;

  25. margin: -50px auto;

  26. }

  27. #my-form {

  28. width: 560px;

  29. height: 450px;

  30. margin: 0 auto;

  31. border: 1px solid #ccc;

  32. padding: 3em;

  33. border-radius: 3px;

  34. box-shadow: 0 0 2px rgba(0, 0, 0, .2);

  35. }

  36. </style>

  37. <script type="text/javascript" src="/assets/scripts/jquery-1.8.2.min.js"></script>

  38. <script type="text/javascript" src="/assets/scripts/jquery.idealforms.js"></script>

  39. </head>

  40. <body>

  41. <!-- style="background-image: url(static/image/bg.jpg) -->

  42. <div class="main" >

  43. <div style="height:5px;text-align:center;font-size:25px"> 欢迎您注册!</div>

  44. <!-- Begin Form -->

  45. <form id="my-form" class="myform">

  46. <div>

  47. <label>用户名:</label><input id="username" name="username" type="text" />

  48. </div>

  49. <div>

  50. <!-- <label>密码:</label><input id="pass" name="password" type="password" /> -->

  51. <label>密码:</label><input id="pass" name="password" type="text" />

  52. </div>

  53. <div>

  54. <label>邮箱:</label><input id="email" name="email"

  55. data-ideal="required email" type="email" />

  56. </div>

  57. <div>

  58. <label>电话:</label><input id="telephone" type="text" name="phone" data-ideal="phone" />

  59. </div>

  60. <div>

  61. <label>供应商V码:</label><input id="vCode" type="text" name="vCode" data-ideal="vCode" />

  62. </div>

  63. <div>

  64. <label>真实姓名:</label><input id="trueName" type="text" name="trueName" data-ideal="trueName" />

  65. </div>

  66. <div>

  67. <label>手机验证码:</label><input id="telCode" type="text" name="telCode" data-ideal="telCode" />

  68. </div>

  69. <div style="margin-bottom:5px;">

  70. <button id="getTelCode" type="button" style="margin-left:160px; margin-right:auto;" >获取手机校验码</button>

  71. <hr style="margin-top:5px; margin-bottom:5px;" />

  72. </div>

  73. <!--<div>

  74. <label>性别:</label>

  75. <select id="sex" name="sex">

  76. <option value="男"></option>

  77. <option value="女"></option>

  78. </select>

  79. </div>

  80. <div>

  81. <label>昵称:</label><input id="nickName" type="text" name="nickName" data-ideal="nickName" />

  82. </div>

  83. <div>

  84. nbsp; <label>年龄:</label><input id="age" type="text" name="age" data-ideal="age" />

  85. </div>-->

  86. <!-- <div>

  87. <label>地址:</label><input type="text" name="address" data-ideal="address" />

  88. </div>

  89. <div>

  90. <label>QQ:</label><input type="text" name="qq" data-ideal="qq" />

  91. </div>

  92. <div>

  93. <label>邮编:</label><input type="text" name="zip" data-ideal="zip" />

  94. </div>

  95. <div>

  96. <label>传真:</label><input type="text" name="fax" data-ideal="fax" />

  97. </div>

  98. <div>

  99. <label>身份证:</label><input type="text" name="creditID" data-ideal="creditID" />

  100. </div>

  101. <div>

  102. <label>出生日期:</label><input name="date" class="datepicker"

  103. data-ideal="date" type="text" placeholder="月/日/年" />

  104. </div>

  105. <div>

  106. <label>上传头像:</label><input id="file" name="file" multiple

  107. type="file" />

  108. </div>

  109. <div>

  110. <label>个人主页:</label><input name="website" data-ideal="url"

  111. type="text" />

  112. </div>

  113. <div>

  114. <label>备注:</label>

  115. <textarea id="comments" name="comments"></textarea>

  116. </div>

  117. -->

  118. <!-- <div id="languages">

  119. <label>语言:</label> <label><input type="checkbox"

  120. name="langs[]" value="English" />英文</label> <label><input

  121. type="checkbox" name="langs[]" value="Chinese" />中文</label> <label><input

  122. type="checkbox" name="langs[]" value="Spanish" />西班牙文</label> <label><input

  123. type="checkbox" name="langs[]" value="French" />法文</label>

  124. </div>

  125. <div>

  126. <label>精通几门:</label> <label><input type="radio"

  127. name="radio" checked />1</label> <label><input type="radio"

  128. name="radio" />2</label> <label><input type="radio" name="radio" />3</label>

  129. <label><input type="radio" name="radio" />4</label>

  130. </div>

  131. <div>

  132. <label>国籍:</label> <select id="states" name="states">

  133. <option value="default">&ndash; 选择国籍 &ndash;</option>

  134. <option value="AL">阿拉伯</option>

  135. <option value="AK">中国</option>

  136. <option value="AZ">美国</option>

  137. <option value="AR">法国</option>

  138. <option value="CA">英国</option>

  139. <option value="CO">德国</option>

  140. <option value="CT">西班牙</option>

  141. <option value="DE">俄罗斯</option>

  142. </select>

  143. </div> -->

  144. <div style="margin-top:10px; margin-left:100px;margin-right:100px;">

  145. <button type="button" id="submit" class="submit">提交</button>

  146. <button id="reset" type="button" >重置</button>

  147. </div>

  148. </form>

  149. <!-- End Form -->

  150. </div>

  151. <script type="text/javascript">

  152. var options = {

  153. onFail : function() {

  154. alert($myform.getInvalid().length + ' invalid fields.')

  155. },

  156. inputs : {

  157. 'password' : {

  158. filters : 'required pass'

  159. },

  160. 'username' : {

  161. filters : 'required username'

  162. },

  163. 'email' : {

  164. filters : 'required email'

  165. },

  166. 'phone' : {

  167. filters : 'required phone'

  168. },

  169. 'trueName' : {

  170. filters : 'required'

  171. },

  172. 'vCode' : {

  173. filters : 'required'

  174. },

  175. 'telCode' : {

  176. filters : 'required'

  177. }

  178. /*

  179. 'age' : {

  180. filters : 'required digits',

  181. data : {

  182. min : 16,

  183. max : 70

  184. }

  185. },

  186. 'file' : {

  187. filters : 'extension',

  188. data : {

  189. extension : [ 'jpg' ]

  190. }

  191. },

  192. 'comments' : {

  193. filters : 'min max',

  194. data : {

  195. min : 50,

  196. max : 200

  197. }

  198. },

  199. 'states' : {

  200. filters : 'exclude',

  201. data : {

  202. exclude : [ 'default' ]

  203. },

  204. errors : {

  205. exclude : '选择国籍.'

  206. }

  207. },

  208. 'langs[]' : {

  209. filters : 'min max',

  210. data : {

  211. min : 2,

  212. max : 3

  213. },

  214. errors : {

  215. min : 'Check at least <strong>2</strong> options.',

  216. max : 'No more than <strong>3</strong> options allowed.'

  217. }

  218. }

  219. */

  220. }

  221. };

  222. $('#getTelCode').click(function() {

  223. var telephone = document.getElementById("telephone").value; //手机号码

  224. if (telephone == null || telephone == ""){

  225. alert("手机号码不能为空!");

  226. }

  227. else{

  228. $.ajax({

  229. type : "GET",

  230. dataType : "json",

  231. url : "../api/getTelCode?telephone="+ telephone,

  232. success : function(msg) {

  233. },

  234. error : function(e) {

  235. alert("获取手机校验码失败!" + e);

  236. }

  237. });

  238. }

  239. });

  240. var $myform = $('#my-form').idealforms(options).data('idealforms');

  241. $('#submit').click(function() {

  242. var username = document.getElementById("username").value; //用户名

  243. var password = document.getElementById("pass").value; //密码

  244. var email = document.getElementById("email").value; //邮箱

  245. var telephone = document.getElementById("telephone").value; //手机号码

  246. var vCode = document.getElementById("vCode").value; //公司V码

  247. var telCode = document.getElementById("telCode").value; //手机校验码

  248. var trueName = document.getElementById("trueName").value; //真实姓名

  249. $.ajax({

  250. type : "GET",

  251. url : "../api/usersRegister?username="+ username +"password="+ password +"email="+ email +"telephone="+ telephone +"vCode="+ vCode +"telCode="+ telCode +"trueName="+ trueName,

  252. success : function(msg) {

  253. //获取当前网址,如: http://localhost:8083/uimcardprj/share/meun.jsp

  254. var curWwwPath = window.document.location.href;

  255. //获取主机地址之后的目录,如: uimcardprj/share/meun.jsp

  256. var pathName = window.document.location.pathname;

  257. var pos = curWwwPath.indexOf(pathName);

  258. //获取主机地址,如: http://localhost:8083

  259. var localhostPaht = curWwwPath.substring(0, pos);

  260. //获取带"/"的项目名,如:/uimcardprj

  261. var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);

  262. window.location.href = projectName + "/login";

  263. alert("注册成功!");

  264. },

  265. error : function(e) {

  266. alert("注册失败!" + e);

  267. }

  268. });

  269. });

  270. $('#reset').click(function() {

  271. $myform.reset().fresh().focusFirst();

  272. });

  273. </script>

  274. </body>

  275. </html>

2.jq输入校验:jquery.idealforms.js

该js校验初始版本来自Cedric Ruiz,我略有修改。

部分校验的规则如下:

required: '此处是必填的.'

number: '必须是数字.',

digits: '必须是唯一的数字.'

name: '必须至少有3个字符长,并且只能包含字母.'

username: '用户名最短5位,最长30位,请使用英文字母、数字、中文和下划线. 用户名首字符必须为字母、数字、中文,不能为全数字.中文最长21个字.'

pass: '密码的位数必须的在6-15位之间,并且至少包含一个数字,一个大写字母和一个小写字母.'

strongpass: '必须至少为8个字符长,至少包含一个大写字母和一个小写字母和一个数字或特殊字符.'

email: '必须是一个有效的email地址. <em>(例: user@gmail.com)</em>'

phone: '必须是一个有效的手机号码. <em>(例: 18723101212)</em>'

以下是整个代码文件:

XML/HTML Code复制内容到剪贴板
  1. /*--------------------------------------------------------------------------

  2. jq-idealforms 2.1

  3. * Author: Cedric Ruiz

  4. * License: GPL or MIT

  5. * Demo: http://elclanrs.github.com/jq-idealforms/

  6. *

  7. --------------------------------------------------------------------------*/

  8. ;(function ( $, window, document, undefined ) {

  9. 'use strict';

  10. // Global Ideal Forms namespace

  11. $.idealforms = {}

  12. $.idealforms.filters = {}

  13. $.idealforms.errors = {}

  14. $.idealforms.flags = {}

  15. $.idealforms.ajaxRequests = {}

  16. /*--------------------------------------------------------------------------*/

  17. /**

  18. * @namespace A chest for various Utils

  19. */

  20. var Utils = {

  21. /**

  22. * Get width of widest element in the collection.

  23. * @memberOf Utils

  24. * @param {jQuery object} $elms

  25. * @returns {number}

  26. */

  27. getMaxWidth: function( $elms ) {

  28. var maxWidth = 0

  29. $elms.each(function() {

  30. var width = $(this).outerWidth()

  31. if ( width > maxWidth ) {

  32. maxWidth = width

  33. }

  34. })

  35. return maxWidth

  36. },

  37. /**

  38. * Hacky way of getting LESS variables

  39. * @memberOf Utils

  40. * @param {string} name The name of the LESS class.

  41. * @param {string} prop The css property where the data is stored.

  42. * @returns {number, string}

  43. */

  44. getLessVar: function( name, prop ) {

  45. var value = $('<p class="' + name + '"></p>').hide().appendTo('body').css( prop )

  46. $('.' + name).remove()

  47. return ( /^\d+/.test( value ) ? parseInt( value, 10 ) : value )

  48. },

  49. /**

  50. * Like ES5 Object.keys

  51. */

  52. getKeys: function( obj ) {

  53. var keys = []

  54. for(var key in obj) {

  55. if ( obj.hasOwnProperty( key ) ) {

  56. keys.push( key )

  57. }

  58. }

  59. return keys

  60. },

  61. // Get lenght of an object

  62. getObjSize: function( obj ) {

  63. var size = 0, key;

  64. for ( key in obj ) {

  65. if ( obj.hasOwnProperty( key ) ) {

  66. size++;

  67. }

  68. }

  69. return size;

  70. },

  71. isFunction: function( obj ) {

  72. return typeof obj ===&nbspnbsp;'function'

  73. },

  74. isRegex: function( obj ) {

  75. return obj instanceof RegExp

  76. },

  77. isString: function( obj ) {

  78. return typeof obj === 'string'

  79. },

  80. getByNameOrId: function( str ) {

  81. var $el = $('[name="'+ str +'"]').length

  82. ? $('[name="'+ str +'"]') // by name

  83. : $('#'+ str) // by id

  84. return $el.length

  85. ? $el

  86. : $.error('The field "'+ str + '" doesn\'t exist.')

  87. },

  88. getFieldsFromArray: function( fields ) {

  89. var f = []

  90. for ( var i = 0, l = fields.length; i < l; i++ ) {

  91. f.push( Utils.getByNameOrId( fields[i] ).get(0) )

  92. }

  93. return $( f )

  94. },

  95. convertToArray: function( obj ) {

  96. return Object.prototype.toString.call( obj ) === '[object Array]'

  97. ? obj : [ obj ]

  98. },

  99. /**

  100. * Determine type of any Ideal Forms element

  101. * @param $input jQuery $input object

  102. */

  103. getIdealType: function( $el ) {

  104. var type = $el.attr('type') || $el[0].tagName.toLowerCase()

  105. return (

  106. /(text|password|email|number|search|url|tel|textarea)/.test( type ) && 'text' ||

  107. /file/.test( type ) && 'file' ||

  108. /select/.test( type ) && 'select' ||

  109. /(radio|checkbox)/.test( type ) && 'radiocheck' ||

  110. /(button|submit|reset)/.test( type ) && 'button' ||

  111. /h\d/.test( type ) && 'heading' ||

  112. /hr/.test( type ) && 'separator' ||

  113. /hidden/.test( type ) && 'hidden'

  114. )

  115. },

  116. /**

  117. * Generates an input

  118. * @param name `name` attribute of the input

  119. * @param type `type` or `tagName` of the input

  120. */

  121. makeInput: function( name, value, type, list, placeholder ) {

  122. var markup, items = [], item, i, len

  123. function splitValue( str ) {

  124. var item, value, arr

  125. if ( /::/.test( str ) ) {

  126. arr = str.split('::')

  127. item = arr[ 0 ]

  128. value = arr[ 1 ]

  129. } else {

  130. item = value = str

  131. }

  132. return { item: item, value: value }

  133. }

  134. // Text & file

  135. if ( /^(text|password|email|number|search|url|tel|file|hidden)$/.test(type) )

  136. markup = '<input '+

  137. 'type="'+ type +'" '+

  138. 'id="'+ name +'" '+

  139. 'name="'+ name +'" '+

  140. 'value="'+ value +'" '+

  141. (placeholder && 'placeholder="'+ placeholder +'"') +

  142. '/>'

  143. // Textarea

  144. if ( /textarea/.test( type ) ) {

  145. markup = '<textarea id="'+ name +'" name="'+ name +'" value="'+ value +'"></textarea>'

  146. }

  147. // Select

  148. if ( /select/.test( type ) ) {

  149. items = []

  150. for ( i = 0, len = list.length; i < len; i++ ) {

  151. item = splitValue( list[ i ] ).item

  152. value = splitValue( list[ i ] ).value

  153. items.push('<option value="'+ value +'">'+ item +'</option>')

  154. }

  155. markup =

  156. '<select id="'+ name +'" name="'+ name +'">'+

  157. items.join('') +

  158. '</select>'

  159. }

  160. // Radiocheck

  161. if ( /(radio|checkbox)/.test( type ) ) {

  162. items = []

  163. for ( i = 0, len = list.length; i < len; i++ ) {

  164. item = splitValue( list[ i ] ).item

  165. value = splitValue( list[ i ] ).value

  166. items.push(

  167. '<label>'+

  168. '<input type="'+ type +'" name="'+ name +'" value="'+ value +'" />'+

  169. item +

  170. '</label>'

  171. )

  172. }

  173. markup = items.join('')

  174. }

  175. return markup

  176. }

  177. }

  178. /**

  179. * Custom tabs for Ideal Forms

  180. */

  181. $.fn.idealTabs = function (container) {

  182. var

  183. // Elements

  184. $contents = this,

  185. $containercontainer = container,

  186. $wrapper = $('<ul class="ideal-tabs-wrap"/>'),

  187. $tabs = (function () {

  188. var tabs = []

  189. $contents.each(function () {

  190. var name = $(this).attr('name')

  191. var html =

  192. '<li class="ideal-tabs-tab">'+

  193. '<span>' + name + '</span>'+

  194. '<i class="ideal-tabs-tab-counter ideal-tabs-tab-counter-zero">0</i>'+

  195. '</li>'

  196. tabs.push(html)

  197. })

  198. return $(tabs.join(''))

  199. }()),

  200. Actions = {

  201. getCurIdx: function () {

  202. return $tabs

  203. .filter('.ideal-tabs-tab-active')

  204. .index()

  205. },

  206. getTabIdxByName: function (name) {

  207. var re = new RegExp(name, 'i')

  208. var $tab = $tabs.filter(function () {

  209. return re.test($(this).text())

  210. })

  211. return $tab.index()

  212. }

  213. },

  214. /**

  215. * Public methods

  216. */

  217. Methods = {

  218. /**

  219. * Switch tab

  220. */

  221. switchTab: function (nameOrIdx) {

  222. var idx = Utils.isString(nameOrIdx)

  223. ? Actions.getTabIdxByName(nameOrIdx)

  224. : nameOrIdx

  225. $tabs.removeClass('ideal-tabs-tab-active')

  226. $tabs.eq(idx).addClass('ideal-tabs-tab-active')

  227. $contents.hide().eq(idx).show()

  228. },

  229. nextTab: function () {

  230. var idx = Actions.getCurIdx() + 1

  231. idx > $tabs.length - 1

  232. ? Methods.firstTab()

  233. : Methods.switchTab(idx)

  234. },

  235. prevTab: function () {

  236. Methods.switchTab(Actions.getCurIdx() - 1)

  237. },

  238. firstTab: function () {

  239. Methods.switchTab(0)

  240. },

  241. lastTab: function () {

  242. Methods.switchTab($tabs.length - 1)

  243. },

  244. updateCounter: function (nameOrIdx, text) {

  245. var idx = !isNaN(nameOrIdx) ? nameOrIdx : Actions.getTabIdxByName(name),

  246. $counter = $tabs.eq(idx).find('.ideal-tabs-tab-counter')

  247. $counter.removeClass('ideal-tabs-tab-counter-zero')

  248. if (!text) {

  249. $counter.addClass('ideal-tabs-tab-counter-zero')

  250. }

  251. $counter.html(text)

  252. }

  253. }

  254. // Attach methods

  255. for (var m in Methods)

  256. $contents[m] = Methods[m]

  257. // Init

  258. $tabs.first()

  259. .addClass('ideal-tabs-tab-active')

  260. .end()

  261. .click(function () {

  262. var name = $(this).text()

  263. $contents.switchTab(name)

  264. })

  265. // Insert in DOM & Events

  266. $wrapper.append($tabs).appendTo($container)

  267. $contents.addClass('ideal-tabs-content')

  268. $contents.each(function () {

  269. var $this = $(this), name = $(this).attr('name')

  270. $this.data('ideal-tabs-content-name', name)

  271. .removeAttr('name')

  272. })

  273. $contents.hide().first().show() // Start fresh

  274. return $contents

  275. }

  276. /**

  277. * A custom <select> menu jQuery plugin

  278. * @example `$('select').idealSelect()`

  279. */

  280. $.fn.idealSelect = function () {

  281. return this.each(function () {

  282. var

  283. $select = $(this),

  284. $options&nbnbsp;= $select.find('option')

  285. /**

  286. * Generate markup and return elements of custom select

  287. * @memberOf $.fn.toCustomSelect

  288. * @returns {object} All elements of the new select replacement

  289. */

  290. var idealSelect = (function () {

  291. var

  292. $wrap = $('<ul class="ideal-select '+ $select.attr('name') +'"/>'),

  293. $menu = $(

  294. '<li><span class="ideal-select-title">' +

  295. $options.filter(':selected').text() +

  296. '</span></li>'

  297. ),

  298. items = (function () {

  299. var items = []

  300. $options.each(function () {

  301. var $this = $(this)

  302. items.push('<li class="ideal-select-item">' + $this.text() + '</li>')

  303. })

  304. return items

  305. }())

  306. $menu.append('<ul class="ideal-select-sub">' + items.join('') + '</ul>')

  307. $wrap.append($menu)

  308. return {

  309. select: $wrap,

  310. title: $menu.find('.ideal-select-title'),

  311. sub: $menu.find('.ideal-select-sub'),

  312. items: $menu.find('.ideal-select-item')

  313. }

  314. }())

  315. /**

  316. * @namespace Methods of custom select

  317. * @memberOf $.fn.toCustomSelect

  318. */

  319. var Actions = {

  320. getSelectedIdx: function () {

  321. return idealSelect.items

  322. .filter('.ideal-select-item-selected').index()

  323. },

  324. /**

  325. * @private

  326. */

  327. init: (function () {

  328. $select.css({

  329. position: 'absolute',

  330. left: '-9999px'

  331. })

  332. idealSelect.sub.hide()

  333. idealSelect.select.insertAfter($select)

  334. idealSelect.select.css(

  335. 'min-width',

  336. Utils.getMaxWidth(idealSelect.items)

  337. )

  338. idealSelect.items

  339. .eq($options.filter(':selected').index())

  340. .addClass('ideal-select-item-selected')

  341. }()),

  342. noWindowScroll: function (e) {

  343. if (e.which === 40 || e.which === 38 || e.which === 13) {

  344. e.preventDefault()

  345. }

  346. },

  347. // Fix loosing focus when scrolling

  348. // and selecting item with keyboard

  349. focusHack: function () {

  350. setTimeout(function () {

  351. $select.trigger('focus')

  352. }, 1)

  353. },

  354. focus: function () {

  355. idealSelect.select.addClass('ideal-select-focus')

  356. $(document).on('keydown.noscroll', Actions.noWindowScroll)

  357. },

  358. blur: function () {

  359. idealSelect.select

  360. .removeClass('ideal-select-open ideal-select-focus')

  361. $(document).off('.noscroll')

  362. },

  363. scrollIntoView: function (dir) {

  364. var

  365. $selected = idealSelect.items.filter('.ideal-select-item-selected'),

  366. itemHeight = idealSelect.items.outerHeight(),

  367. menuHeight = idealSelect.sub.outerHeight(),

  368. isInView = (function () {

  369. // relative position to the submenu

  370. var elPos = $selected.position().top + itemHeight

  371. return dir === 'down'

  372. ? elPos <= menuHeight

  373. : elPos > 0

  374. }())

  375. if (!isInView) {

  376. itemHeight = (dir === 'down')

  377. ? itemHeight // go down

  378. : -itemHeight // go up

  379. idealSelect.sub

  380. .scrollTop(idealSelect.sub.scrollTop() + itemHeight)

  381. }

  382. },

  383. scrollToItem: function () {

  384. var idx = Actions.getSelectedIdx(),

  385. height = idealSelect.items.outerHeight(),

  386. nItems = idealSelect.items.length,

  387. allHeight = height * nItems,

  388. curHeight = height * (nItems - idx)

  389. idealSelect.sub.scrollTop(allHeight - curHeight)

  390. },

  391. showMenu: function () {

  392. idealSelect.sub.fadeIn('fast')

  393. idealSelect.select.addClass('ideal-select-open')

  394. Actions.select(Actions.getSelectedIdx())

  395. Actions.scrollToItem()

  396. },

  397. hideMenu: function () {

  398. idealSelect.sub.hide()

  399. idealSelect.select.removeClass('ideal-select-open')

  400. },

  401. select: function (idx) {

  402. idealSelect.items

  403. .removeClass('ideal-select-item-selected')

  404. idealSelect.items

  405. .eq(idx).addClass('ideal-select-item-selected')

  406. },

  407. change: function (idx) {

  408. var text = idealSelect.items.eq(idx).text()

  409. Actions.select(idx)

  410. idealSelect.title.text(text)

  411. $options.eq(idx).prop('selected', true)

  412. $select.trigger('change')

  413. },

  414. keydown: function (key) {

  415. var

  416. idx = Actions.getSelectedIdx(),

  417. isMenu = idealSelect.select.is('.ideal-select-menu'),

  418. isOpen = idealSelect.select.is('.ideal-select-open')

  419. /**

  420. * @namespace Key pressed

  421. */

  422. var keys = {

  423. 9: function () { // TAB

  424. if (isMenu) {

  425. Actions.blur()

  426. Actions.hideMenu()

  427. }

  428. },

  429. 13: function () { // ENTER

  430. if (isMenu)

  431. isOpen

  432. ? Actions.hideMenu()

  433. : Actions.showMenu()

  434. Actions.change(idx)

  435. },

  436. 27: function () { // ESC

  437. if (isMenu) Actions.hideMenu()

  438. },

  439. 40: function () { // DOWN

  440. if (idx < $options.length - 1) {

  441. isOpen

  442. ? Actions.select(idx + 1)

  443. : Actions.change(idx + 1)

  444. }

  445. Actions.scrollIntoView('down')

  446. },

  447. 38: function () { // UP

  448. if (idx > 0) {

  449. isOpen

  450. ? Actions.select(idx - 1)

  451. : Actions.change(idx - 1)

  452. }

  453. Actions.scrollIntoView('up')

  454. },

  455. 'default': function () { // Letter

  456. var

  457. letter = String.fromCharCode(key),

  458. $matches = idealSelect.items

  459. .filter(function () {

  460. return /^\w+$/i.test( letter ) && // not allow modifier keys ( ctrl, cmd, meta, super... )

  461. new RegExp('^' + letter, 'i').test( $(this).text() ) // find first match

  462. }),

  463. nMatches = $matches.length,

  464. counter = idealSelect.select.data('counter') + 1 || 0,

  465. curKey = idealSelect.select.data('key') || key,

  466. newIdx = $matches.eq(counter).index()

  467. if (!nMatches) // No matches

  468. return false

  469. // If more matches with same letter

  470. if (curKey === key) {

  471. if (counter < nMatches) {

  472. idealSelect.select.data('counter', counter)

  473. }

  474. else {

  475. idealSelect.select.data('counter', 0)

  476. newIdx = $matches.eq(0).index()

  477. }

  478. }

  479. // If new letter

  480. else {

  481. &nnbsp;idealSelect.select.data('counter', 0)

  482. newIdx = $matches.eq(0).index()

  483. }

  484. if (isOpen)

  485. Actions.select(newIdx)

  486. else

  487. Actions.change(newIdx)

  488. idealSelect.select.data('key', key)

  489. Actions.scrollToItem()

  490. Actions.focusHack()

  491. }

  492. }

  493. keys[key]

  494. ? keys[key]()

  495. : keys['default']()

  496. }

  497. }

  498. /**

  499. * @namespace Holds all events of custom select for "menu mode" and "list mode"

  500. * @memberOf $.fn.toCustomSelect

  501. */

  502. var events = {

  503. focus: Actions.focus,

  504. 'blur.menu': function () {

  505. Actions.blur()

  506. Actions.hideMenu()

  507. },

  508. 'blur.list': function () {

  509. Actions.blur()

  510. },

  511. keydown: function (e) {

  512. Actions.keydown(e.which)

  513. },

  514. 'clickItem.menu': function () {

  515. Actions.change($(this).index())

  516. Actions.hideMenu()

  517. },

  518. 'clickItem.list': function () {

  519. Actions.change($(this).index())

  520. },

  521. 'clickTitle.menu': function () {

  522. Actions.focus()

  523. Actions.showMenu()

  524. $select.trigger('focus')

  525. },

  526. 'hideOutside.menu': function () {

  527. $select.off('blur.menu')

  528. $(document).on('mousedown.ideal', function (evt) {

  529. if (!$(evt.target).closest(idealSelect.select).length) {

  530. $(document).off('mousedown.ideal')

  531. $select.on('blur.menu', events['blur.menu'])

  532. } else {

  533. Actions.focusHack()

  534. }

  535. })

  536. },

  537. 'mousedown.list': function () {

  538. Actions.focusHack()

  539. }

  540. }

  541. // Reset events

  542. var disableEvents = function () {

  543. idealSelect.select.removeClass('ideal-select-menu ideal-select-list')

  544. $select.off('.menu .list')

  545. idealSelect.items.off('.menu .list')

  546. idealSelect.select.off('.menu .list')

  547. idealSelect.title.off('.menu .list')

  548. }

  549. // Menu mode

  550. idealSelect.select.on('menu', function () {

  551. disableEvents()

  552. idealSelect.select.addClass('ideal-select-menu')

  553. Actions.hideMenu()

  554. $select.on({

  555. 'blur.menu': events['blur.menu'],

  556. 'focus.menu': events.focus,

  557. 'keydown.menu': events.keydown

  558. })

  559. idealSelect.select.on('mousedown.menu', events['hideOutside.menu'])

  560. idealSelect.items.on('click.menu', events['clickItem.menu'])

  561. idealSelect.title.on('click.menu', events['clickTitle.menu'])

  562. })

  563. // List mode

  564. idealSelect.select.on('list', function () {

  565. disableEvents()

  566. idealSelect.select.addClass('ideal-select-list')

  567. Actions.showMenu()

  568. $select.on({

  569. 'blur.list': events['blur.list'],

  570. 'focus.list': events.focus,

  571. 'keydown.list': events.keydown

  572. })

  573. idealSelect.select.on('mousedown.list', events['mousedown.list'])

  574. idealSelect.items.on('mousedown.list', events['clickItem.list'])

  575. })

  576. $select.keydown(function (e) {

  577. // Prevent default keydown event

  578. // to avoid bugs with Ideal Select events

  579. if (e.which !== 9) e.preventDefault()

  580. })

  581. // Reset

  582. idealSelect.select.on('reset', function(){

  583. Actions.change(0)

  584. })

  585. idealSelect.select.trigger('menu') // Default to "menu mode"

  586. })

  587. }

  588. /*

  589. * idealRadioCheck: jQuery plguin for checkbox and radio replacement

  590. * Usage: $('input[type=checkbox], input[type=radio]').idealRadioCheck()

  591. */

  592. $.fn.idealRadioCheck = function() {

  593. return this.each(function() {

  594. var $this = $(this)

  595. var $span = $('<span/>')

  596. $span.addClass( 'ideal-'+ ( $this.is(':checkbox') ? 'check' : 'radio' ) )

  597. $this.is(':checked') && $span.addClass('checked') // init

  598. $span.insertAfter( $this )

  599. $this.parent('label').addClass('ideal-radiocheck-label')

  600. .attr('onclick', '') // Fix clicking label in iOS

  601. $this.css({ position: 'absolute', left: '-9999px' }) // hide by shifting left

  602. // Events

  603. $this.on({

  604. change: function() {

  605. var $this = $(this)

  606. if ( $this.is('input[type="radio"]') ) {

  607. $this.parent().siblings('label').find('.ideal-radio').removeClass('checked')

  608. }

  609. $span.toggleClass( 'checked', $this.is(':checked') )

  610. },

  611. focus: function() { $span.addClass('focus') },

  612. blur: function() { $span.removeClass('focus') },

  613. click: function() { $(this).trigger('focus') }

  614. })

  615. })

  616. }

  617. ;(function( $ ) {

  618. // Browser supports HTML5 multiple file?

  619. var multipleSupport = typeof $('<input/>')[0].multiple !== 'undefined',

  620. isIE = /msie/i.test( navigator.userAgent )

  621. $.fn.idealFile = function() {

  622. return this.each(function() {

  623. var $file = $(this).addClass('ideal-file'), // the original file input

  624. // label that will be used for IE hack

  625. $wrap = $('<div class="ideal-file-wrap">'),

  626. $input = $('<input type="text" class="ideal-file-filename" />'),

  627. // Button that will be used in non-IE browsers

  628. $button = $('<button type="button" class="ideal-file-upload">Open</button>'),

  629. // Hack for IE

  630. $label = $('<label class="ideal-file-upload" for="'+ $file[0].id +'">Open</label>')

  631. // Hide by shifting to the left so we

  632. // can still trigger events

  633. $file.css({

  634. position: 'absolute',

  635. left: '-9999px'

  636. })

  637. $wrap.append( $input, ( isIE ? $label : $button ) ).insertAfter( $file )

  638. // Prevent focus

  639. $file.attr('tabIndex', -1)

  640. $button.attr('tabIndex', -1)

  641. $button.click(function () {

  642. $file.focus().click() // Open dialog

  643. })

  644. $file.change(function() {

  645. var files = [], fileArr, filename

  646. // If multiple is supported then extract

  647. // all filenames from the file array

  648. if ( multipleSupport ) {

  649. fileArr = $file[0].files

  650. for ( var i = 0, len = fileArr.length; i < len; i++ ) {

  651. files.push( fileArr[i].name )

  652. }

  653. filename = files.join(', ')

  654. // If not supported then just take the value

  655. // and remove the path to just show the filename

  656. } else {

  657. filename = $file.val().split('\\').pop()

  658. }

  659. $input.val( filename ) // Set the value

  660. .attr( 'title', filename ) // Show filename in title tootlip

  661. })

  662. $input.on({

  663. focus: function () { $file.trigger('change') },

  664. blur: function () { $file.trigger('blur') },

  665. keydown: function( e ) {

  666. if ( e.which === 13 ) { // Enter

  667. if ( !isIE ) { $file.trigger('click') }

  668. } else if ( e.which === 8 || e.which === 46 ) { // Backspace & Del

  669. // On some browsers the value is read-only

  670. // with this trick we remove the old input and add

  671. // a clean clone with all the original events attached

  672. $file.replaceWith( $file = $file.val('').clone( true ) )

  673. $file.trigger('change')

  674. $input.val('')

  675. } else if ( e.which === 9 ){ // TAB

  676. return

  677. } else { // All other keys

  678. return false

  679. }

  680. }

  681. })

  682. })

  683. }

  684. }( jQuery ))

  685. /**

  686. * @namespace Errors

  687. * @locale en

  688. */

  689. $.idealforms.errors = {

  690. required: '此处是必填的.',

  691. number: '必须是数字.',

  692. digits: '必须是唯一的数字.',

  693. name: '必须至少有3个字符长,并且只能包含字母.',

  694. username: '用户名最短5位,最长30位,请使用英文字母、数字、中文和下划线.用户名首字符必须为字母、数字、中文,不能为全数字.中文最长21个字.',

  695. pass: '密码的位数必须的在6-15位之间,并且至少包含一个数字,一个大写字母和一个小写字母.',

  696. strongpass: '必须至少为8个字符长,至少包含一个大写字母和一个小写字母和一个数字或特殊字符.',

  697. email: '必须是一个有效的email地址. <em>(例: user@gmail.com)</em>',

  698. phone: '必须是一个有效的手机号码. <em>(例: 18723101212)</em>',

  699. zip: 'Must be a valid US zip code. <em>(e.g. 33245 or 33245-0003)</em>',

  700. url: 'Must be a valid URL. <em>(e.g. www.google.com)</em>',

  701. minChar: 'Must be at least <strong>{0}</strong> characters long.',

  702. minOption: 'Check at least <strong>{0}</strong> options.',

  703. maxChar: 'No more than <strong>{0}</strong> characters long.',

  704. maxOption: 'No more than <strong>{0}</strong> options allowed.',

  705. range: 'Must be a number between {0} and {1}.',

  706. date: 'Must be a valid date. <em>(e.g. {0})</em>',

  707. dob: 'Must be a valid date of birth.',

  708. exclude: '"{0}" is not available.',

  709. excludeOption: '{0}',

  710. equalto: 'Must be the same value as <strong>"{0}"</strong>',

  711. extension: 'File(s) must have a valid extension. <em>(e.g. "{0}")</em>',

  712. ajaxSuccess: '<strong>{0}</strong> is not available.',

  713. ajaxError: 'Server error...'

  714. }

  715. /**

  716. * Get all default filters

  717. * @returns object

  718. */

  719. var getFilters = function() {

  720. var filters = {

  721. required: {

  722. regex: /.+/,

  723. error: $.idealforms.errors.required

  724. },

  725. number: {

  726. regex: function( i, v ) { return !isNaN(v) },

  727. error: $.idealforms.errors.number

  728. },

  729. digits: {

  730. regex: /^\d+$/,

  731. error: $.idealforms.errors.digits

  732. },

  733. name: {

  734. regex: /^[A-Za-z]{3,}$/,

  735. error: $.idealforms.errors.name

  736. },

  737. username: {

  738. regex: /^[a-z](?=[\w.]{4,30}$)\w*\.?\w*$/i,

  739. error: $.idealforms.errors.username

  740. },

  741. pass: {

  742. regex: /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/,

  743. error: $.idealforms.errors.pass

  744. },

  745. strongpass: {

  746. regex: /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/,

  747. error: $.idealforms.errors.strongpass

  748. },

  749. email: {

  750. 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})?$/,

  751. error: $.idealforms.errors.email

  752. },

  753. phone: {

  754. //regex: /^((13[0-9])|(15[0-9])|(17[0-9])|(18[0-9]))\\d{8}$/,

  755. regex: /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/,

  756. error: $.idealforms.errors.phone

  757. },

  758. zip: {

  759. regex: /^\d{5}$|^\d{5}-\d{4}$/,

  760. error: $.idealforms.errors.zip

  761. },

  762. url: {

  763. regex: /^(?:(ftp|http|https):\/\/)?(?:[\w\-]+\.)+[a-z]{2,6}([\:\/?#].*)?$/i,

  764. error: $.idealforms.errors.url

  765. },

  766. min: {

  767. regex: function( input, value ) {

  768. var $inputinput = input.input,

  769. min = input.userOptions.data.min,

  770. isRadioCheck = $input.is('[type="checkbox"], [type="radio"]')

  771. if ( isRadioCheck ) {

  772. this.error = $.idealforms.errors.minOption.replace( '{0}', min )

  773. return $input.filter(':checked').length >= min

  774. }

  775. this.error = $.idealforms.errors.minChar.replace( '{0}', min )

  776. return value.length >= min

  777. }

  778. },

  779. max: {

  780. regex: function( input, value ) {

  781. var $inputinput = input.input,

  782. max = input.userOptions.data.max,

  783. isRadioCheck = $input.is('[type="checkbox"], [type="radio"]')

  784. if ( isRadioCheck ) {

  785. this.error = $.idealforms.errors.maxOption.replace( '{0}', max )

  786. return $input.filter(':checked').length <= max

  787. }

  788. this.error = $.idealforms.errors.maxChar.replace( '{0}', max )

  789. return value.length <= max

  790. }

  791. },

  792. range: {

  793. regex: function( input, value ) {

  794. var range = input.userOptions.data.range,

  795. val = +value

  796. this.error = $.idealforms.errors.range

  797. .replace( '{0}', range[0] )

  798. .replace( '{1}', range[1] )

  799. return val >= range[0] && val <= range[1]

  800. }

  801. },

  802. date: {

  803. regex: function( input, value ) {

  804. var

  805. userFormat =

  806. input.userOptions.data && input.userOptions.data.date

  807. ? input.userOptions.data.date

  808. : 'mm/dd/yyyy', // default format

  809. delimiter = /[^mdy]/.exec( userFormat )[0],

  810. theFormat = userFormat.split(delimiter),

  811. theDate = value.split(delimiter),

  812. isDate = function( date, format ) {

  813. var m, d, y

  814. for ( var i = 0, len = format.length; i < len; i++ ) {

  815. if ( /m/.test( format[i]) ) m = date[i]

  816. if ( /d/.test( format[i]) ) d = date[i]

  817. if ( /y/.test( format[i]) ) y = date[i]

  818. }

  819. return (

  820. m > 0 && m < 13 &&

  821. y && y.length === 4 &&

  822. d > 0 && d <= ( new Date( y, m, 0 ) ).getDate()

  823. )

  824. }

  825. this.error = $.idealforms.errors.date.replace( '{0}', userFormat )

  826. return isDate( theDate, theFormat )

  827. }

  828. },

  829. dob: {

  830. regex: function( input, value ) {

  831. var

  832. userFormat =

  833. input.userOptions.data && input.userOptions.data.dob

  834. ? input.userOptions.data.dob

  835. : 'mm/dd/yyyy', // default format

  836. // Simulate a date input

  837. dateInput = {

  838. input: input.input,

  839. userOptions: {

  840. data: { date: userFormat }

  841. }

  842. },

  843. // Use internal date filter to validate the date

  844. isDate = filters.date.regex( dateInput, value ),

  845. // DOB

  846. theYear = /\d{4}/.exec( value ),

  847. maxYear = new Date().getFullYear(), // Current year

  848. minYear = maxYear - 100

  849. this.error = $.idealforms.errors.dob

  850. return isDate && theYear >= minYear && theYear <= maxYear

  851. }

  852. },

  853. exclude: {

  854. regex: function( input, value ) {

  855. var $inputinput = input.input,

  856. exclude = input.userOptions.data.exclude,

  857. isOption = $input.is('[type="checkbox"], [type="radio"], select')

  858. this.error = isOption

  859. ? $.idealforms.errors.excludeOption.replace( '{0}', value )

  860. : this.error = $.idealforms.errors.exclude.replace( '{0}', value )

  861. return $.inArray( value, exclude ) === -1

  862. }

  863. },

  864. equalto: {

  865. regex: function( input, value ) {

  866. var $equals = $( input.userOptions.data.equalto ),

  867. $inputinput = input.input,

  868. name = $equals.attr('name') || $equals.attr('id'),

  869. isValid = $equals.parents('.ideal-field')

  870. .filter(function(){ return $(this).data('ideal-isvalid') === true })

  871. .length

  872. if ( !isValid ) { return false }

  873. this.error = $.idealforms.errors.equalto.replace( '{0}', name )

  874. return $input.val() === $equals.val()

  875. }

  876. },

  877. extension: {

  878. regex: function( input, value ) {

  879. nbsp;var files = input.input[0].files || [{ name: value }],

  880. extensions = input.userOptions.data.extension,

  881. re = new RegExp( '\\.'+ extensions.join('|') +'$', 'i' ),

  882. valid = false

  883. for ( var i = 0, len = files.length; i < len; i++ ) {

  884. valid = re.test( files[i].name );

  885. }

  886. this.error = $.idealforms.errors.extension.replace( '{0}', extensions.join('", "') )

  887. return valid

  888. }

  889. },

  890. ajax: {

  891. regex: function( input, value, showOrHideError ) {

  892. var self = this

  893. var $inputinput = input.input

  894. var userOptions = input.userOptions

  895. var name = $input.attr('name')

  896. var $field = $input.parents('.ideal-field')

  897. var valid = false

  898. var customErrors = userOptions.errors && userOptions.errors.ajax

  899. self.error = {}

  900. self.error.success = customErrors && customErrors.success

  901. ? customErrors.success

  902. : $.idealforms.errors.ajaxSuccess.replace( '{0}', value )

  903. self.error.fail = customErrors && customErrors.error

  904. ? customErrors.error

  905. : $.idealforms.errors.ajaxError

  906. // Send input name as $_POST[name]

  907. var data = {}

  908. data[ name ] = $.trim( value )

  909. // Ajax options defined by the user

  910. var userAjaxOps = input.userOptions.data.ajax

  911. var ajaxOps = {

  912. type: 'post',

  913. dataType: 'json',

  914. data: data,

  915. success: function( resp, text, xhr ) {

  916. console.log(resp)

  917. showOrHideError( self.error.success, true )

  918. $input.data({

  919. 'ideal-ajax-resp': resp,

  920. 'ideal-ajax-error': self.error.success

  921. })

  922. $input.trigger('change') // to update counter

  923. $field.removeClass('ajax')

  924. // Run custom success callback

  925. if( userAjaxOps._success ) {

  926. userAjaxOps._success( resp, text, xhr )

  927. }

  928. },

  929. error: function( xhr, text, error ) {

  930. if ( text !== 'abort' ) {

  931. showOrHideError( self.error.fail, false )

  932. $input.data( 'ideal-ajax-error', self.error.fail )

  933. $field.removeClass('ajax')

  934. // Run custom error callback

  935. if ( userAjaxOps._error ) {

  936. userAjaxOps._error( xhr, text, error )

  937. }

  938. }

  939. }

  940. }

  941. $.extend( ajaxOps, userAjaxOps )

  942. // Init

  943. $input.removeData('ideal-ajax-error')

  944. $input.removeData('ideal-ajax-resp')

  945. $field.addClass('ajax')

  946. // Run request and save it to be able to abort it

  947. // so requests don't bubble

  948. $.idealforms.ajaxRequests[ name ] = $.ajax( ajaxOps )

  949. }

  950. }

  951. }

  952. return filters

  953. }

  954. $.idealforms.flags = {

  955. noerror: function (i) {

  956. i.parent().siblings('.ideal-error').hide()

  957. },

  958. noicons: function (i) {

  959. i.siblings('.ideal-icon-valid, .ideal-icon-invalid').hide()

  960. },

  961. novalidicon: function (i) {

  962. i.siblings('.ideal-icon-valid').hide()

  963. },

  964. noinvalidicon: function (i) {

  965. i.siblings('.ideal-icon-invalid').hide()

  966. },

  967. noclass: function (i) {

  968. i.parents('.ideal-field').removeClass('valid invalid')

  969. },

  970. novalidclass: function (i) {

  971. i.parents('.ideal-field').removeClass('valid')

  972. },

  973. noinvalidclass: function (i) {

  974. i.parents('.ideal-field').removeClass('invalid')

  975. }

  976. }

  977. /*

  978. * Ideal Forms plugin

  979. */

  980. var _defaults = {

  981. inputs: {},

  982. customFilters: {},

  983. customFlags: {},

  984. globalFlags: '',

  985. onSuccess: function(e) { alert('Thank you...') },

  986. onFail: function() { alert('Invalid!') },

  987. responsiveAt: 'auto',

  988. disableCustom: ''

  989. }

  990. // Constructor

  991. var IdealForms = function( element, options ) {

  992. var self = this

  993. self.$form = $( element )

  994. self.opts = $.extend( {}, _defaults, options )

  995. self.$tabs = self.$form.find('section')

  996. // Set localized filters

  997. $.extend( $.idealforms.filters, getFilters() )

  998. self._init()

  999. }

  1000. // Plugin

  1001. $.fn.idealforms = function( options ) {

  1002. return this.each(function() {

  1003. if ( !$.data( this, 'idealforms' ) ) {

  1004. $.data( this, 'idealforms', new IdealForms( this, options ) )

  1005. }

  1006. })

  1007. }

  1008. // Get LESS variables

  1009. var LessVars = {

  1010. fieldWidth: Utils.getLessVar( 'ideal-field-width', 'width' )

  1011. }

  1012. /*

  1013. * Private Methods

  1014. */

  1015. $.extend( IdealForms.prototype, {

  1016. _init: function() {

  1017. var self = this

  1018. var o = self.opts

  1019. var formElements = self._getFormElements()

  1020. self.$form.css( 'visibility', 'visible' )

  1021. .addClass('ideal-form')

  1022. .attr( 'novalidate', 'novalidate' ) // disable HTML5 validation

  1023. // Do markup

  1024. formElements.inputs

  1025. .add( formElements.headings )

  1026. .add( formElements.separators )

  1027. .each(function(){ self._doMarkup( $(this) ) })

  1028. // Generate tabs

  1029. if ( self.$tabs.length ) {

  1030. var $tabContainer = $('<div class="ideal-wrap ideal-tabs ideal-full-width"/>')

  1031. self.$form.prepend( $tabContainer )

  1032. self.$tabs.idealTabs( $tabContainer )

  1033. }

  1034. // Always show datepicker below the input

  1035. if ( jQuery.ui ) {

  1036. $.datepicker._checkOffset = function( a,b,c ) { return b }

  1037. }

  1038. // Add inputs specified by data-ideal

  1039. // to the list of user inputs

  1040. self.$form.find('[data-ideal]').each(function() {

  1041. var userInput = o.inputs[ this.name ]

  1042. o.inputs[ this.name ] = userInput || { filters: $(this).data('ideal') }

  1043. })

  1044. // Responsive

  1045. if ( o.responsiveAt ) {

  1046. $(window).resize(function(){ self._responsive() })

  1047. self._responsive()

  1048. }

  1049. // Form events

  1050. self.$form.on({

  1051. keydown: function( e ) {

  1052. // Prevent submit when pressing enter

  1053. // but exclude textareas

  1054. if ( e.which === 13 && e.target.nodeName !== 'TEXTAREA' ) {

  1055. e.preventDefault()

  1056. }

  1057. },

  1058. submit: function( e ) {

  1059. if ( !self.isValid() ) {

  1060. e.preventDefault()

  1061. o.onFail()

  1062. self.focusFirstInvalid()

  1063. } else {

  1064. o.onSuccess( e )

  1065. }

  1066. }

  1067. })

  1068. self._adjust()

  1069. self._attachEvents()

  1070. self.fresh() // Start fresh

  1071. },

  1072. _getFormElements: function() {

  1073. return {

  1074. inputs: this.$form.find('input, select, textarea, :button'),

  1075. labels: this.$form.find('div > label:first-child'),

  1076. text: this.$form.find('input:not([type="checkbox"], [type="radio"], [type="submit"]), textarea'),

  1077. select: this.$form.find('select'),

  1078. radiocheck: this.$form.find('input[type="radio"], input[type="checkbox"]'),

  1079. buttons: this.$form.find(':button'),

  1080. file: this.$form.find('input[type="file"]'),

  1081. headings: this.$form.find('h1, h2, h3, h4, h5, h6'),

  1082. separators: this.$form.find('hr'),

  1083. hidden: this.$form.find('input:hidden')

  1084. }

  1085. },

  1086. _getUserInputs: function() {

  1087. return this.$form.find('[name="'+ Utils.getKeys( this.opts.inputs ).join('"], [name="') +'"]')

  1088. },

  1089. _getTab: function( nameOrIdx ) {

  1090. var self = this

  1091. var isNumber = !isNaN( nameOrIdx )

  1092. if ( isNumber ) {

  1093. return self.$tabs.eq( nameOrIdx )

  1094. }

  1095. return self.$tabs.filter(function() {

  1096. var re = new RegExp( nameOrIdx, 'i' )

  1097. return re.test( nbsp;$(this).data('ideal-tabs-content-name') )

  1098. })

  1099. },

  1100. _getCurrentTabIdx: function() {

  1101. return this.$tabs.index( this.$form.find('.ideal-tabs-content:visible') )

  1102. },

  1103. _updateTabsCounter: function() {

  1104. var self = this

  1105. self.$tabs.each(function( i ) {

  1106. var invalid = self.getInvalidInTab( i ).length

  1107. self.$tabs.updateCounter( i, invalid )

  1108. })

  1109. },

  1110. _adjust: function() {

  1111. var self = this

  1112. var o = self.opts

  1113. var formElements = self._getFormElements()

  1114. var curTab = self._getCurrentTabIdx()

  1115. // Autocomplete causes some problems...

  1116. formElements.inputs.attr('autocomplete', 'off')

  1117. // Show tabs to calculate dimensions

  1118. if ( self.$tabs.length ) { self.$tabs.show() }

  1119. // Adjust labels

  1120. var labels = formElements.labels

  1121. labels.removeAttr('style').width( Utils.getMaxWidth( labels ) )

  1122. // Adjust headings and separators

  1123. if ( self.$tabs.length ) {

  1124. this.$tabs.each(function(){

  1125. $( this ).find('.ideal-heading:first').addClass('first-child')

  1126. })

  1127. } else {

  1128. self.$form.find('.ideal-heading:first').addClass('first-child')

  1129. }

  1130. self._setDatepicker()

  1131. // Done calculating hide tabs

  1132. if ( self.$tabs.length ) {

  1133. self.$tabs.hide()

  1134. self.switchTab( curTab )

  1135. }

  1136. },

  1137. _setDatepicker: function() {

  1138. var o = this.opts

  1139. var $datepicker = this.$form.find('input.datepicker')

  1140. if ( jQuery.ui && $datepicker.length ) {

  1141. $datepicker.each(function() {

  1142. var userInput = o.inputs[ this.name ]

  1143. var data = userInput && userInput.data && userInput.data.date

  1144. var format = data ? data.replace( 'yyyy', 'yy' ) : 'mm/dd/yy'

  1145. $(this).datepicker({

  1146. dateFormat: format,

  1147. beforeShow: function( input ) {

  1148. $( input ).addClass('open')

  1149. },

  1150. onChangeMonthYear: function() {

  1151. // Hack to fix IE9 not resizing

  1152. var $this = $(this)

  1153. var w = $this.outerWidth() // cache first!

  1154. setTimeout(function() {

  1155. $this.datepicker('widget').css( 'width', w )

  1156. }, 1)

  1157. },

  1158. onClose: function() { $(this).removeClass('open') }

  1159. })

  1160. })

  1161. // Adjust width

  1162. $datepicker.on('focus keyup', function() {

  1163. var t = $(this), w = t.outerWidth()

  1164. t.datepicker('widget').css( 'width', w )

  1165. })

  1166. $datepicker.parent().siblings('.ideal-error').addClass('hidden')

  1167. }

  1168. },

  1169. _doMarkup: function( $element ) {

  1170. var o = this.opts

  1171. var elementType = Utils.getIdealType( $element )

  1172. // Validation elements

  1173. var $field = $('<span class="ideal-field"/>')

  1174. var $error = $('<span class="ideal-error" />')

  1175. var $valid = $('<i class="ideal-icon ideal-icon-valid" />')

  1176. var $invalid = $('<i class="ideal-icon ideal-icon-invalid"/>')

  1177. .click(function(){

  1178. $(this).parent().find('input:first, textarea, select').focus()

  1179. })

  1180. // Basic markup

  1181. $element.closest('div').addClass('ideal-wrap')

  1182. .children('label:first-child').addClass('ideal-label')

  1183. var idealElements = {

  1184. _defaultInput: function() {

  1185. $element.wrapAll( $field ).after( $valid, $invalid )

  1186. .parent().after( $error )

  1187. },

  1188. text: function() { idealElements._defaultInput() },

  1189. radiocheck: function() {

  1190. // Check if input is already wrapped so we don't

  1191. // wrap radios and checks more than once

  1192. var isWrapped = $element.parents('.ideal-field').length

  1193. if ( !isWrapped ) {

  1194. $element.parent().nextAll().andSelf().wrapAll( $field.addClass('ideal-radiocheck') )

  1195. $element.parents('.ideal-field').append( $valid, $invalid ).after( $error )

  1196. }

  1197. if ( !/radiocheck/.test( o.disableCustom ) ) {

  1198. $element.idealRadioCheck()

  1199. }

  1200. },

  1201. select: function() {

  1202. idealElements._defaultInput()

  1203. if ( !/select/.test( o.disableCustom ) ) {

  1204. $element.idealSelect()

  1205. }

  1206. },

  1207. file: function() {

  1208. idealElements._defaultInput()

  1209. if ( !/file/.test( o.disableCustom ) ) {

  1210. $element.idealFile()

  1211. }

  1212. },

  1213. button: function() {

  1214. if ( !/button/.test( o.disableCustom ) ) {

  1215. $element.addClass('ideal-button')

  1216. }

  1217. },

  1218. hidden: function() {

  1219. $element.closest('div').addClass('ideal-hidden')

  1220. },

  1221. heading: function() {

  1222. $element.closest('div').addClass('ideal-full-width')

  1223. $element.parent().children().wrapAll('<span class="ideal-heading"/>')

  1224. },

  1225. separator: function() {

  1226. $element.closest('div').addClass('ideal-full-width')

  1227. $element.wrapAll('<div class="ideal-separator"/>')

  1228. }

  1229. }

  1230. // Generate markup for current element type

  1231. idealElements[ elementType ] ? idealElements[ elementType ]() : $.noop()

  1232. $error.add( $valid ).add( $invalid ).hide() // Start fresh

  1233. },

  1234. /** Validates an input and shows or hides error and icon

  1235. * @memberOf Actions

  1236. * @param {object} $input jQuery object

  1237. * @param {string} e The JavaScript event

  1238. */

  1239. _validate: function( $input, e ) {

  1240. var self = this

  1241. var o = this.opts

  1242. var userOptions = o.inputs[ $input.attr('name') ]

  1243. var userFilters = userOptions.filters && userOptions.filters.split(/\s/)

  1244. var name = $input.attr('name')

  1245. var value = $input.val()

  1246. var ajaxRequest = $.idealforms.ajaxRequests[ name ]

  1247. var isRadioCheck = $input.is('[type="checkbox"], [type="radio"]')

  1248. var inputData = {

  1249. // If is radio or check validate all inputs related by name

  1250. input: isRadioCheck ? self.$form.find('[name="' + name + '"]') : $input,

  1251. userOptions: userOptions

  1252. }

  1253. // Validation elements

  1254. var $field = $input.parents('.ideal-field')

  1255. var $error = $field.siblings('.ideal-error')

  1256. var $invalid = isRadioCheck

  1257. ? $input.parent().siblings('.ideal-icon-invalid')

  1258. : $input.siblings('.ideal-icon-invalid')

  1259. var $valid = isRadioCheck

  1260. ? $input.parent().siblings('.ideal-icon-valid')

  1261. : $input.siblings('.ideal-icon-valid')

  1262. function resetError() {

  1263. $field.removeClass('valid invalid').removeData('ideal-isvalid')

  1264. $error.add( $invalid ).add( $valid ).hide()

  1265. }

  1266. function showOrHideError( error, valid ) {

  1267. resetError()

  1268. valid ? $valid.show() : $invalid.show()

  1269. $field.addClass( valid ? 'valid' : 'invalid' )

  1270. $field.data( 'ideal-isvalid', valid )

  1271. if ( !valid ) {

  1272. $error.html( error ).toggle( $field.is('.ideal-field-focus') )

  1273. }

  1274. }

  1275. // Prevent validation when typing but not introducing any new characters

  1276. // This is mainly to prevent multiple AJAX requests

  1277. var oldValue = $input.data('ideal-value') || 0

  1278. $input.data( 'ideal-value', value )

  1279. if ( e.type === 'keyup' && value === oldValue ) { return false }

  1280. // Validate

  1281. if ( userFilters ) {

  1282. $.each( userFilters, function( i, filter ) {

  1283. var theFilter = $.idealforms.filters[ filter ]

  1284. var customError = userOptions.errors && userOptions.errors[ filter ]

  1285. var error = ''

  1286. // If field is empty and not required

  1287. if ( !value && filter !== 'required' ) {

  1288. resetError()

  1289. return false

  1290. }

  1291. if ( theFilter ) {

  1292. // Abort and reset ajax if there's a request pending

  1293. if ( e.type === 'keyup' && ajaxRequest ) {

  1294. ajaxRequest.abort()

  1295. $field.removeClass('ajax')

  1296. }

  1297. // AJAX

  1298. if ( filter === 'ajax' ) {

  1299. nbsp; showOrHideError( error, false ) // set invalid till response comes back

  1300. $error.hide()

  1301. if ( e.type === 'keyup' ) {

  1302. theFilter.regex( inputData, value, showOrHideError ) // runs the ajax callback

  1303. } else {

  1304. var ajaxError = $input.data('ideal-ajax-error')

  1305. if ( ajaxError ) {

  1306. showOrHideError( ajaxError, $input.data('ideal-ajax-resp') || false )

  1307. }

  1308. }

  1309. }

  1310. // All other filters

  1311. else {

  1312. var valid = Utils.isRegex( theFilter.regex ) && theFilter.regex.test( value ) ||

  1313. Utils.isFunction( theFilter.regex ) && theFilter.regex( inputData, value )

  1314. error = customError || theFilter.error // assign error after calling regex()

  1315. showOrHideError( error, valid )

  1316. if ( !valid ) { return false }

  1317. }

  1318. }

  1319. })

  1320. }

  1321. // Reset if there are no filters

  1322. else {

  1323. resetError()

  1324. }

  1325. // Flags

  1326. var flags = (function(){

  1327. var f = userOptions.flags && userOptions.flags.split(' ') || []

  1328. if ( o.globalFlags ) {

  1329. $.each( o.globalFlags.split(' '), function( i,v ) { f.push(v) })

  1330. }

  1331. return f

  1332. }())

  1333. if ( flags.length ) {

  1334. $.each(flags, function( i,f ) {

  1335. var theFlag = $.idealforms.flags[f]

  1336. if ( theFlag ) { theFlag( $input, e.type ) }

  1337. })

  1338. }

  1339. // Update counter

  1340. if ( self.$tabs.length ) {

  1341. self._updateTabsCounter( self._getCurrentTabIdx() )

  1342. }

  1343. },

  1344. _attachEvents: function() {

  1345. var self = this

  1346. self._getUserInputs().on('keyup change focus blur', function(e) {

  1347. var $this = $(this)

  1348. var $field = $this.parents('.ideal-field')

  1349. var isFile = $this.is('input[type=file]')

  1350. // Trigger on change if type=file cuz custom file

  1351. // disables focus on original file input (tabIndex = -1)

  1352. if ( e.type === 'focus' || isFile && e.type === 'change' ) {

  1353. $field.addClass('ideal-field-focus')

  1354. }

  1355. if ( e.type === 'blur' ) {

  1356. $field.removeClass('ideal-field-focus')

  1357. }

  1358. self._validate( $this, e )

  1359. })

  1360. },

  1361. _responsive: function() {

  1362. var formElements = this._getFormElements()

  1363. var maxWidth = LessVars.fieldWidth + formElements.labels.outerWidth()

  1364. var $emptyLabel = formElements.labels.filter(function() {

  1365. return $(this).html() === ' '

  1366. })

  1367. var $customSelect = this.$form.find('.ideal-select')

  1368. this.opts.responsiveAt === 'auto'

  1369. ? this.$form.toggleClass( 'stack', this.$form.width() < maxWidth )

  1370. : this.$form.toggleClass( 'stack', $(window).width() < this.opts.responsiveAt )

  1371. var isStack = this.$form.is('.stack')

  1372. $emptyLabel.toggle( !isStack )

  1373. $customSelect.trigger( isStack ? 'list' : 'menu' )

  1374. // Hide datePicker

  1375. var $datePicker = this.$form.find('input.hasDatepicker')

  1376. if ( $datePicker.length ) { $datePicker.datepicker('hide') }

  1377. }

  1378. })

  1379. /*

  1380. * Public Methods

  1381. */

  1382. $.extend( IdealForms.prototype, {

  1383. getInvalid: function() {

  1384. return this.$form.find('.ideal-field').filter(function() {

  1385. return $(this).data('ideal-isvalid') === false

  1386. })

  1387. },

  1388. getInvalidInTab: function( nameOrIdx ) {

  1389. return this._getTab( nameOrIdx ).find('.ideal-field').filter(function() {

  1390. return $(this).data('ideal-isvalid') === false

  1391. })

  1392. },

  1393. isValid: function() {

  1394. return !this.getInvalid().length

  1395. },

  1396. isValidField: function( field ) {

  1397. var $input = Utils.getByNameOrId( field )

  1398. return $input.parents('.ideal-field').data('ideal-isvalid') === true

  1399. },

  1400. focusFirst: function() {

  1401. if ( this.$tabs.length ) {

  1402. this.$tabs.filter(':visible')

  1403. .find('.ideal-field:first')

  1404. .find('input:first, select, textarea').focus()

  1405. } else {

  1406. this.$form.find('.ideal-field:first')

  1407. .find('input:first, select, textarea').focus()

  1408. }

  1409. return this

  1410. },

  1411. focusFirstInvalid: function() {

  1412. var $first = this.getInvalid().first().find('input:first, select, textarea')

  1413. var tabName = $first.parents('.ideal-tabs-content').data('ideal-tabs-content-name')

  1414. if ( this.$tabs.length ) {

  1415. this.switchTab( tabName )

  1416. }

  1417. $first.focus()

  1418. return this

  1419. },

  1420. switchTab: function( nameOrIdx ) {

  1421. this.$tabs.switchTab( nameOrIdx )

  1422. return this

  1423. },

  1424. nextTab: function() {

  1425. this.$tabs.nextTab()

  1426. return this

  1427. },

  1428. prevTab: function() {

  1429. this.$tabs.prevTab()

  1430. return this

  1431. },

  1432. firstTab: function() {

  1433. this.$tabs.firstTab()

  1434. return this

  1435. },

  1436. lastTab: function() {

  1437. this.$tabs.lastTab()

  1438. return this

  1439. },

  1440. fresh: function() {

  1441. this._getUserInputs().change().parents('.ideal-field')

  1442. .removeClass('valid invalid')

  1443. return this

  1444. },

  1445. freshFields: function( fields ) {

  1446. fields = Utils.convertToArray( fields )

  1447. $.each( fields, function( i ) {

  1448. var $input = Utils.getByNameOrId( fields[ i ] )

  1449. $input.change().parents('.ideal-field').removeClass('valid invalid')

  1450. })

  1451. return this

  1452. },

  1453. reload: function() {

  1454. this._adjust()

  1455. this._attachEvents()

  1456. return this

  1457. },

  1458. reset: function() {

  1459. var formElements = this._getFormElements()

  1460. formElements.text.val('') // text inputs

  1461. formElements.radiocheck.removeAttr('checked') // radio & check

  1462. // Select and custom select

  1463. formElements.select.find('option').first().prop( 'selected', true )

  1464. this.$form.find('.ideal-select').trigger('reset')

  1465. if ( this.$tabs.length ) { this.firstTab() }

  1466. this.focusFirst().fresh()

  1467. return this

  1468. },

  1469. resetFields: function( fields ) {

  1470. fields = Utils.convertToArray( fields )

  1471. var formElements = this._getFormElements()

  1472. $.each( fields, function( i, v ) {

  1473. var $input = Utils.getByNameOrId( v )

  1474. var type = Utils.getIdealType( $input )

  1475. if ( type === 'text' || type === 'file' ) {

  1476. $input.val('')

  1477. }

  1478. if ( type === 'radiocheck' ) {

  1479. $input.removeAttr('checked') // radio & check

  1480. }

  1481. if ( type === 'select' ) {

  1482. $input.find('option').first().prop( 'selected', true )

  1483. $input.next('.ideal-select').trigger('reset')

  1484. }

  1485. $input.change()

  1486. })

  1487. this.freshFields( fields )

  1488. return this

  1489. },

  1490. toggleFields: function( fields ) {

  1491. fields = Utils.convertToArray( fields )

  1492. var self = this

  1493. var $fields = Utils.getFieldsFromArray( fields )

  1494. $fields.each(function() {

  1495. var $this = $(this)

  1496. var name = $this.attr('name') || $this.attr('id')

  1497. var input = self.opts.inputs[ name ]

  1498. var filters = input && input.filters

  1499. var dataFilters = $this.data('ideal-filters') || ''

  1500. $this.data( 'ideal-filters', filters )

  1501. $this.closest('.ideal-wrap').toggle()

  1502. self.setFieldOptions( name, { filters: dataFilters } )

  1503. })

  1504. return this

  1505. },

  1506. setOptions: function( options ) {

  1507. $.extend( true, this.opts, options )

  1508. this.reload().fresh()

  1509. return this

  1510. },

  1511. setFieldOptions: function( name, options ) {

  1512. $.extend( true, this.opts.inputs[ name ], options )

  1513. this.reload().freshFields([ name ])

  1514. return this

  1515. },

  1516. addFields: function( fields ) {

  1517. fields = Utils.convertToArray( fields )

  1518. var self = this

  1519. // Save names of all inputs in Array

  1520. // to use methods that take names ie. fresh()

  1521. var allNames = []

  1522. // Add an input to the DOM

  1523. function add( ops ) {

  1524. var name = ops.name

  1525. &nbspnbsp; var userOptions = {

  1526. filters: ops.filters || '',

  1527. data: ops.data || {},

  1528. errors: ops.errors || {},

  1529. flags: ops.flags || ''

  1530. }

  1531. var label = ops.label || ''

  1532. var type = ops.type

  1533. var list = ops.list || []

  1534. var placeholder = ops.placeholder || ''

  1535. var value = ops.value || ''

  1536. var $field = $('<div>'+

  1537. '<label>'+ label +':</label>'+

  1538. Utils.makeInput( name, value, type, list, placeholder ) +

  1539. '</div>')

  1540. var $input = $field.find('input, select, textarea, :button')

  1541. // Add inputs with filters to the list

  1542. // of user inputs to validate

  1543. if ( userOptions.filters ) { self.opts.inputs[ name ] = userOptions }

  1544. self._doMarkup( $input )

  1545. // Insert in DOM

  1546. if ( ops.addAfter ) {

  1547. $field.insertAfter(

  1548. $( Utils.getByNameOrId( ops.addAfter ) ).parents('.ideal-wrap')

  1549. )

  1550. } else if ( ops.addBefore ) {

  1551. $field.insertBefore(

  1552. $(Utils.getByNameOrId( ops.addBefore ))

  1553. .parents('.ideal-wrap')

  1554. )

  1555. } else if ( ops.appendToTab ) {

  1556. $field.insertAfter(

  1557. self._getTab( ops.appendToTab ).find('.ideal-wrap:last-child')

  1558. )

  1559. } else {

  1560. $field.insertAfter( self.$form.find('.ideal-wrap').last() )

  1561. }

  1562. // Add current field name to list of names

  1563. allNames.push( name )

  1564. }

  1565. // Run through each input

  1566. $.each( fields, function( i, ops ) { add( ops ) })

  1567. self.reload()

  1568. self.freshFields( allNames )

  1569. self._responsive()

  1570. return this

  1571. },

  1572. removeFields: function( fields ) {

  1573. fields = Utils.convertToArray( fields )

  1574. var $fields = Utils.getFieldsFromArray( fields )

  1575. $fields.parents('.ideal-wrap').remove()

  1576. this.reload()

  1577. return this

  1578. }

  1579. })

  1580. }( jQuery, window, document ))

【相关推荐】

1. Html5免费视频教程

2. HTML5本地数据库实例详解

3. 教你如何实现一个H5微场景

4. 详解H5的自定义属性data-*

5. h5实现文本框提示语的代码实例

以上就是H5完成用户注册自动校验的实例详解的详细内容,更多请关注其它相关文章!

相关标签: html5,用户注册