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

05-24 10:49:46作者:php中文网

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

以下是效果截图:

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完成用户注册自动校验的实例详解的详细内容,转载自php中文网

点赞(731) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部