• 技术文章 >web前端 >H5教程

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

    Y2JY2J2017-05-24 13:27:07原创1470

    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中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:html5,用户注册
    上一篇:h5实现文本框提示语的代码实例 下一篇:用H5实现手机摇一摇的实例详解
    PHP编程就业班

    相关文章推荐

    • 深入解析asp.net中mvc4自定义404页面(分享)• html5离线存储有哪些• 在今天,利用 HTML5 开发和发布大型跨平台网游,可行性如何?要解决哪些问题?• 避免常见的六种HTML5错误用法 (5-6)• phonegap使用方法介绍(八)操作数据库

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网