抽时间写了一个带有自动校验功能的Html5用户注册Demo。使用到Handlebars模板技术和手机验证码校验。
以下是效果截图:
1.页面代码:usersRegister.hbs
XML/HTML Code复制内容到剪贴板- <!DOCTYPE html>
- <!--[if IE 8 ]> <html lang="en" class="ie8"> <![endif]-->
- <!--[if IE 9 ]> <html lang="en" class="ie9"> <![endif]-->
- <!--[if (gt IE 9)|!(IE)]><!-->
- <html lang="en">
- <!--<![endif]-->
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge" />
- <title>用户注册</title>
- <!--[if lt IE 9]>
- <script src="/assets/scripts/html5shiv.js"></script>
- <![endif]-->
- <link href="/assets/styles/jquery.idealforms.min.css" rel="stylesheet" media="screen" />
- <style type="text/css">
- body {
- font: normal 15px/1.5 Arial, Helvetica, Free Sans, sans-serif;
- color: #222;
- overflow-y: scroll;
- padding: 60px 0 0 0;
- }
- .main {
- width: 560px;
- height: 480px;
- margin: -50px auto;
- }
- #my-form {
- width: 560px;
- height: 450px;
- margin: 0 auto;
- border: 1px solid #ccc;
- padding: 3em;
- border-radius: 3px;
- box-shadow: 0 0 2px rgba(0, 0, 0, .2);
- }
- </style>
- <script type="text/javascript" src="/assets/scripts/jquery-1.8.2.min.js"></script>
- <script type="text/javascript" src="/assets/scripts/jquery.idealforms.js"></script>
- </head>
- <body>
- <!-- style="background-image: url(static/image/bg.jpg) -->
- <div class="main" >
- <div style="height:5px;text-align:center;font-size:25px"> 欢迎您注册!</div>
- <!-- Begin Form -->
- <form id="my-form" class="myform">
- <div>
- <label>用户名:</label><input id="username" name="username" type="text" />
- </div>
- <div>
- <!-- <label>密码:</label><input id="pass" name="password" type="password" /> -->
- <label>密码:</label><input id="pass" name="password" type="text" />
- </div>
- <div>
- <label>邮箱:</label><input id="email" name="email"
- data-ideal="required email" type="email" />
- </div>
- <div>
- <label>电话:</label><input id="telephone" type="text" name="phone" data-ideal="phone" />
- </div>
- <div>
- <label>供应商V码:</label><input id="vCode" type="text" name="vCode" data-ideal="vCode" />
- </div>
- <div>
- <label>真实姓名:</label><input id="trueName" type="text" name="trueName" data-ideal="trueName" />
- </div>
- <div>
- <label>手机验证码:</label><input id="telCode" type="text" name="telCode" data-ideal="telCode" />
- </div>
- <div style="margin-bottom:5px;">
- <button id="getTelCode" type="button" style="margin-left:160px; margin-right:auto;" >获取手机校验码</button>
- <hr style="margin-top:5px; margin-bottom:5px;" />
- </div>
- <!--<div>
- <label>性别:</label>
- <select id="sex" name="sex">
- <option value="男">男</option>
- <option value="女">女</option>
- </select>
- </div>
- <div>
- <label>昵称:</label><input id="nickName" type="text" name="nickName" data-ideal="nickName" />
- </div>
- <div>
- <label>年龄:</label><input id="age" type="text" name="age" data-ideal="age" />
- </div>-->
- <!-- <div>
- <label>地址:</label><input type="text" name="address" data-ideal="address" />
- </div>
- <div>
- <label>QQ:</label><input type="text" name="qq" data-ideal="qq" />
- </div>
- <div>
- <label>邮编:</label><input type="text" name="zip" data-ideal="zip" />
- </div>
- <div>
- <label>传真:</label><input type="text" name="fax" data-ideal="fax" />
- </div>
- <div>
- <label>身份证:</label><input type="text" name="creditID" data-ideal="creditID" />
- </div>
- <div>
- <label>出生日期:</label><input name="date" class="datepicker"
- data-ideal="date" type="text" placeholder="月/日/年" />
- </div>
- <div>
- <label>上传头像:</label><input id="file" name="file" multiple
- type="file" />
- </div>
- <div>
- <label>个人主页:</label><input name="website" data-ideal="url"
- type="text" />
- </div>
- <div>
- <label>备注:</label>
- <textarea id="comments" name="comments"></textarea>
- </div>
- -->
- <!-- <div id="languages">
- <label>语言:</label> <label><input type="checkbox"
- name="langs[]" value="English" />英文</label> <label><input
- type="checkbox" name="langs[]" value="Chinese" />中文</label> <label><input
- type="checkbox" name="langs[]" value="Spanish" />西班牙文</label> <label><input
- type="checkbox" name="langs[]" value="French" />法文</label>
- </div>
- <div>
- <label>精通几门:</label> <label><input type="radio"
- name="radio" checked />1</label> <label><input type="radio"
- name="radio" />2</label> <label><input type="radio" name="radio" />3</label>
- <label><input type="radio" name="radio" />4</label>
- </div>
- <div>
- <label>国籍:</label> <select id="states" name="states">
- <option value="default">– 选择国籍 –</option>
- <option value="AL">阿拉伯</option>
- <option value="AK">中国</option>
- <option value="AZ">美国</option>
- <option value="AR">法国</option>
- <option value="CA">英国</option>
- <option value="CO">德国</option>
- <option value="CT">西班牙</option>
- <option value="DE">俄罗斯</option>
- </select>
- </div> -->
- <div style="margin-top:10px; margin-left:100px;margin-right:100px;">
- <button type="button" id="submit" class="submit">提交</button>
- <button id="reset" type="button" >重置</button>
- </div>
- </form>
- <!-- End Form -->
- </div>
- <script type="text/javascript">
- var options = {
- onFail : function() {
- alert($myform.getInvalid().length + ' invalid fields.')
- },
- inputs : {
- 'password' : {
- filters : 'required pass'
- },
- 'username' : {
- filters : 'required username'
- },
- 'email' : {
- filters : 'required email'
- },
- 'phone' : {
- filters : 'required phone'
- },
- 'trueName' : {
- filters : 'required'
- },
- 'vCode' : {
- filters : 'required'
- },
- 'telCode' : {
- filters : 'required'
- }
- /*
- 'age' : {
- filters : 'required digits',
- data : {
- min : 16,
- max : 70
- }
- },
- 'file' : {
- filters : 'extension',
- data : {
- extension : [ 'jpg' ]
- }
- },
- 'comments' : {
- filters : 'min max',
- data : {
- min : 50,
- max : 200
- }
- },
- 'states' : {
- filters : 'exclude',
- data : {
- exclude : [ 'default' ]
- },
- errors : {
- exclude : '选择国籍.'
- }
- },
- 'langs[]' : {
- filters : 'min max',
- data : {
- min : 2,
- max : 3
- },
- errors : {
- min : 'Check at least <strong>2</strong> options.',
- max : 'No more than <strong>3</strong> options allowed.'
- }
- }
- */
- }
- };
- $('#getTelCode').click(function() {
- var telephone = document.getElementById("telephone").value; //手机号码
- if (telephone == null || telephone == ""){
- alert("手机号码不能为空!");
- }
- else{
- $.ajax({
- type : "GET",
- dataType : "json",
- url : "../api/getTelCode?telephone="+ telephone,
- success : function(msg) {
- },
- error : function(e) {
- alert("获取手机校验码失败!" + e);
- }
- });
- }
- });
- var $myform = $('#my-form').idealforms(options).data('idealforms');
- $('#submit').click(function() {
- var username = document.getElementById("username").value; //用户名
- var password = document.getElementById("pass").value; //密码
- var email = document.getElementById("email").value; //邮箱
- var telephone = document.getElementById("telephone").value; //手机号码
- var vCode = document.getElementById("vCode").value; //公司V码
- var telCode = document.getElementById("telCode").value; //手机校验码
- var trueName = document.getElementById("trueName").value; //真实姓名
- $.ajax({
- type : "GET",
- url : "../api/usersRegister?username="+ username +"password="+ password +"email="+ email +"telephone="+ telephone +"vCode="+ vCode +"telCode="+ telCode +"trueName="+ trueName,
- success : function(msg) {
- //获取当前网址,如: http://localhost:8083/uimcardprj/share/meun.jsp
- var curWwwPath = window.document.location.href;
- //获取主机地址之后的目录,如: uimcardprj/share/meun.jsp
- var pathName = window.document.location.pathname;
- var pos = curWwwPath.indexOf(pathName);
- //获取主机地址,如: http://localhost:8083
- var localhostPaht = curWwwPath.substring(0, pos);
- //获取带"/"的项目名,如:/uimcardprj
- var projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
- window.location.href = projectName + "/login";
- alert("注册成功!");
- },
- error : function(e) {
- alert("注册失败!" + e);
- }
- });
- });
- $('#reset').click(function() {
- $myform.reset().fresh().focusFirst();
- });
- </script>
- </body>
- </html>
2.jq输入校验:jquery.idealforms.js
该js校验初始版本来自Cedric Ruiz,我略有修改。
部分校验的规则如下:
required: '此处是必填的.'
number: '必须是数字.',
digits: '必须是唯一的数字.'
name: '必须至少有3个字符长,并且只能包含字母.'
username: '用户名最短5位,最长30位,请使用英文字母、数字、中文和下划线. 用户名首字符必须为字母、数字、中文,不能为全数字.中文最长21个字.'
pass: '密码的位数必须的在6-15位之间,并且至少包含一个数字,一个大写字母和一个小写字母.'
strongpass: '必须至少为8个字符长,至少包含一个大写字母和一个小写字母和一个数字或特殊字符.'
email: '必须是一个有效的email地址. <em>(例: user@gmail.com)</em>'
phone: '必须是一个有效的手机号码. <em>(例: 18723101212)</em>'
以下是整个代码文件:
XML/HTML Code复制内容到剪贴板- /*--------------------------------------------------------------------------
- jq-idealforms 2.1
- * Author: Cedric Ruiz
- * License: GPL or MIT
- * Demo: http://elclanrs.github.com/jq-idealforms/
- *
- --------------------------------------------------------------------------*/
- ;(function ( $, window, document, undefined ) {
- 'use strict';
- // Global Ideal Forms namespace
- $.idealforms = {}
- $.idealforms.filters = {}
- $.idealforms.errors = {}
- $.idealforms.flags = {}
- $.idealforms.ajaxRequests = {}
- /*--------------------------------------------------------------------------*/
- /**
- * @namespace A chest for various Utils
- */
- var Utils = {
- /**
- * Get width of widest element in the collection.
- * @memberOf Utils
- * @param {jQuery object} $elms
- * @returns {number}
- */
- getMaxWidth: function( $elms ) {
- var maxWidth = 0
- $elms.each(function() {
- var width = $(this).outerWidth()
- if ( width > maxWidth ) {
- maxWidth = width
- }
- })
- return maxWidth
- },
- /**
- * Hacky way of getting LESS variables
- * @memberOf Utils
- * @param {string} name The name of the LESS class.
- * @param {string} prop The css property where the data is stored.
- * @returns {number, string}
- */
- getLessVar: function( name, prop ) {
- var value = $('<p class="' + name + '"></p>').hide().appendTo('body').css( prop )
- $('.' + name).remove()
- return ( /^\d+/.test( value ) ? parseInt( value, 10 ) : value )
- },
- /**
- * Like ES5 Object.keys
- */
- getKeys: function( obj ) {
- var keys = []
- for(var key in obj) {
- if ( obj.hasOwnProperty( key ) ) {
- keys.push( key )
- }
- }
- return keys
- },
- // Get lenght of an object
- getObjSize: function( obj ) {
- var size = 0, key;
- for ( key in obj ) {
- if ( obj.hasOwnProperty( key ) ) {
- size++;
- }
- }
- return size;
- },
- isFunction: function( obj ) {
- return typeof obj === 'function'
- },
- isRegex: function( obj ) {
- return obj instanceof RegExp
- },
- isString: function( obj ) {
- return typeof obj === 'string'
- },
- getByNameOrId: function( str ) {
- var $el = $('[name="'+ str +'"]').length
- ? $('[name="'+ str +'"]') // by name
- : $('#'+ str) // by id
- return $el.length
- ? $el
- : $.error('The field "'+ str + '" doesn\'t exist.')
- },
- getFieldsFromArray: function( fields ) {
- var f = []
- for ( var i = 0, l = fields.length; i < l; i++ ) {
- f.push( Utils.getByNameOrId( fields[i] ).get(0) )
- }
- return $( f )
- },
- convertToArray: function( obj ) {
- return Object.prototype.toString.call( obj ) === '[object Array]'
- ? obj : [ obj ]
- },
- /**
- * Determine type of any Ideal Forms element
- * @param $input jQuery $input object
- */
- getIdealType: function( $el ) {
- var type = $el.attr('type') || $el[0].tagName.toLowerCase()
- return (
- /(text|password|email|number|search|url|tel|textarea)/.test( type ) && 'text' ||
- /file/.test( type ) && 'file' ||
- /select/.test( type ) && 'select' ||
- /(radio|checkbox)/.test( type ) && 'radiocheck' ||
- /(button|submit|reset)/.test( type ) && 'button' ||
- /h\d/.test( type ) && 'heading' ||
- /hr/.test( type ) && 'separator' ||
- /hidden/.test( type ) && 'hidden'
- )
- },
- /**
- * Generates an input
- * @param name `name` attribute of the input
- * @param type `type` or `tagName` of the input
- */
- makeInput: function( name, value, type, list, placeholder ) {
- var markup, items = [], item, i, len
- function splitValue( str ) {
- var item, value, arr
- if ( /::/.test( str ) ) {
- arr = str.split('::')
- item = arr[ 0 ]
- value = arr[ 1 ]
- } else {
- item = value = str
- }
- return { item: item, value: value }
- }
- // Text & file
- if ( /^(text|password|email|number|search|url|tel|file|hidden)$/.test(type) )
- markup = '<input '+
- 'type="'+ type +'" '+
- 'id="'+ name +'" '+
- 'name="'+ name +'" '+
- 'value="'+ value +'" '+
- (placeholder && 'placeholder="'+ placeholder +'"') +
- '/>'
- // Textarea
- if ( /textarea/.test( type ) ) {
- markup = '<textarea id="'+ name +'" name="'+ name +'" value="'+ value +'"></textarea>'
- }
- // Select
- if ( /select/.test( type ) ) {
- items = []
- for ( i = 0, len = list.length; i < len; i++ ) {
- item = splitValue( list[ i ] ).item
- value = splitValue( list[ i ] ).value
- items.push('<option value="'+ value +'">'+ item +'</option>')
- }
- markup =
- '<select id="'+ name +'" name="'+ name +'">'+
- items.join('') +
- '</select>'
- }
- // Radiocheck
- if ( /(radio|checkbox)/.test( type ) ) {
- items = []
- for ( i = 0, len = list.length; i < len; i++ ) {
- item = splitValue( list[ i ] ).item
- value = splitValue( list[ i ] ).value
- items.push(
- '<label>'+
- '<input type="'+ type +'" name="'+ name +'" value="'+ value +'" />'+
- item +
- '</label>'
- )
- }
- markup = items.join('')
- }
- return markup
- }
- }
- /**
- * Custom tabs for Ideal Forms
- */
- $.fn.idealTabs = function (container) {
- var
- // Elements
- $contents = this,
- $containercontainer = container,
- $wrapper = $('<ul class="ideal-tabs-wrap"/>'),
- $tabs = (function () {
- var tabs = []
- $contents.each(function () {
- var name = $(this).attr('name')
- var html =
- '<li class="ideal-tabs-tab">'+
- '<span>' + name + '</span>'+
- '<i class="ideal-tabs-tab-counter ideal-tabs-tab-counter-zero">0</i>'+
- '</li>'
- tabs.push(html)
- })
- return $(tabs.join(''))
- }()),
- Actions = {
- getCurIdx: function () {
- return $tabs
- .filter('.ideal-tabs-tab-active')
- .index()
- },
- getTabIdxByName: function (name) {
- var re = new RegExp(name, 'i')
- var $tab = $tabs.filter(function () {
- return re.test($(this).text())
- })
- return $tab.index()
- }
- },
- /**
- * Public methods
- */
- Methods = {
- /**
- * Switch tab
- */
- switchTab: function (nameOrIdx) {
- var idx = Utils.isString(nameOrIdx)
- ? Actions.getTabIdxByName(nameOrIdx)
- : nameOrIdx
- $tabs.removeClass('ideal-tabs-tab-active')
- $tabs.eq(idx).addClass('ideal-tabs-tab-active')
- $contents.hide().eq(idx).show()
- },
- nextTab: function () {
- var idx = Actions.getCurIdx() + 1
- idx > $tabs.length - 1
- ? Methods.firstTab()
- : Methods.switchTab(idx)
- },
- prevTab: function () {
- Methods.switchTab(Actions.getCurIdx() - 1)
- },
- firstTab: function () {
- Methods.switchTab(0)
- },
- lastTab: function () {
- Methods.switchTab($tabs.length - 1)
- },
- updateCounter: function (nameOrIdx, text) {
- var idx = !isNaN(nameOrIdx) ? nameOrIdx : Actions.getTabIdxByName(name),
- $counter = $tabs.eq(idx).find('.ideal-tabs-tab-counter')
- $counter.removeClass('ideal-tabs-tab-counter-zero')
- if (!text) {
- $counter.addClass('ideal-tabs-tab-counter-zero')
- }
- $counter.html(text)
- }
- }
- // Attach methods
- for (var m in Methods)
- $contents[m] = Methods[m]
- // Init
- $tabs.first()
- .addClass('ideal-tabs-tab-active')
- .end()
- .click(function () {
- var name = $(this).text()
- $contents.switchTab(name)
- })
- // Insert in DOM & Events
- $wrapper.append($tabs).appendTo($container)
- $contents.addClass('ideal-tabs-content')
- $contents.each(function () {
- var $this = $(this), name = $(this).attr('name')
- $this.data('ideal-tabs-content-name', name)
- .removeAttr('name')
- })
- $contents.hide().first().show() // Start fresh
- return $contents
- }
- /**
- * A custom <select> menu jQuery plugin
- * @example `$('select').idealSelect()`
- */
- $.fn.idealSelect = function () {
- return this.each(function () {
- var
- $select = $(this),
- $options = $select.find('option')
- /**
- * Generate markup and return elements of custom select
- * @memberOf $.fn.toCustomSelect
- * @returns {object} All elements of the new select replacement
- */
- var idealSelect = (function () {
- var
- $wrap = $('<ul class="ideal-select '+ $select.attr('name') +'"/>'),
- $menu = $(
- '<li><span class="ideal-select-title">' +
- $options.filter(':selected').text() +
- '</span></li>'
- ),
- items = (function () {
- var items = []
- $options.each(function () {
- var $this = $(this)
- items.push('<li class="ideal-select-item">' + $this.text() + '</li>')
- })
- return items
- }())
- $menu.append('<ul class="ideal-select-sub">' + items.join('') + '</ul>')
- $wrap.append($menu)
- return {
- select: $wrap,
- title: $menu.find('.ideal-select-title'),
- sub: $menu.find('.ideal-select-sub'),
- items: $menu.find('.ideal-select-item')
- }
- }())
- /**
- * @namespace Methods of custom select
- * @memberOf $.fn.toCustomSelect
- */
- var Actions = {
- getSelectedIdx: function () {
- return idealSelect.items
- .filter('.ideal-select-item-selected').index()
- },
- /**
- * @private
- */
- init: (function () {
- $select.css({
- position: 'absolute',
- left: '-9999px'
- })
- idealSelect.sub.hide()
- idealSelect.select.insertAfter($select)
- idealSelect.select.css(
- 'min-width',
- Utils.getMaxWidth(idealSelect.items)
- )
- idealSelect.items
- .eq($options.filter(':selected').index())
- .addClass('ideal-select-item-selected')
- }()),
- noWindowScroll: function (e) {
- if (e.which === 40 || e.which === 38 || e.which === 13) {
- e.preventDefault()
- }
- },
- // Fix loosing focus when scrolling
- // and selecting item with keyboard
- focusHack: function () {
- setTimeout(function () {
- $select.trigger('focus')
- }, 1)
- },
- focus: function () {
- idealSelect.select.addClass('ideal-select-focus')
- $(document).on('keydown.noscroll', Actions.noWindowScroll)
- },
- blur: function () {
- idealSelect.select
- .removeClass('ideal-select-open ideal-select-focus')
- $(document).off('.noscroll')
- },
- scrollIntoView: function (dir) {
- var
- $selected = idealSelect.items.filter('.ideal-select-item-selected'),
- itemHeight = idealSelect.items.outerHeight(),
- menuHeight = idealSelect.sub.outerHeight(),
- isInView = (function () {
- // relative position to the submenu
- var elPos = $selected.position().top + itemHeight
- return dir === 'down'
- ? elPos <= menuHeight
- : elPos > 0
- }())
- if (!isInView) {
- itemHeight = (dir === 'down')
- ? itemHeight // go down
- : -itemHeight // go up
- idealSelect.sub
- .scrollTop(idealSelect.sub.scrollTop() + itemHeight)
- }
- },
- scrollToItem: function () {
- var idx = Actions.getSelectedIdx(),
- height = idealSelect.items.outerHeight(),
- nItems = idealSelect.items.length,
- allHeight = height * nItems,
- curHeight = height * (nItems - idx)
- idealSelect.sub.scrollTop(allHeight - curHeight)
- },
- showMenu: function () {
- idealSelect.sub.fadeIn('fast')
- idealSelect.select.addClass('ideal-select-open')
- Actions.select(Actions.getSelectedIdx())
- Actions.scrollToItem()
- },
- hideMenu: function () {
- idealSelect.sub.hide()
- idealSelect.select.removeClass('ideal-select-open')
- },
- select: function (idx) {
- idealSelect.items
- .removeClass('ideal-select-item-selected')
- idealSelect.items
- .eq(idx).addClass('ideal-select-item-selected')
- },
- change: function (idx) {
- var text = idealSelect.items.eq(idx).text()
- Actions.select(idx)
- idealSelect.title.text(text)
- $options.eq(idx).prop('selected', true)
- $select.trigger('change')
- },
- keydown: function (key) {
- var
- idx = Actions.getSelectedIdx(),
- isMenu = idealSelect.select.is('.ideal-select-menu'),
- isOpen = idealSelect.select.is('.ideal-select-open')
- /**
- * @namespace Key pressed
- */
- var keys = {
- 9: function () { // TAB
- if (isMenu) {
- Actions.blur()
- Actions.hideMenu()
- }
- },
- 13: function () { // ENTER
- if (isMenu)
- isOpen
- ? Actions.hideMenu()
- : Actions.showMenu()
- Actions.change(idx)
- },
- 27: function () { // ESC
- if (isMenu) Actions.hideMenu()
- },
- 40: function () { // DOWN
- if (idx < $options.length - 1) {
- isOpen
- ? Actions.select(idx + 1)
- : Actions.change(idx + 1)
- }
- Actions.scrollIntoView('down')
- },
- 38: function () { // UP
- if (idx > 0) {
- isOpen
- ? Actions.select(idx - 1)
- : Actions.change(idx - 1)
- }
- Actions.scrollIntoView('up')
- },
- 'default': function () { // Letter
- var
- letter = String.fromCharCode(key),
- $matches = idealSelect.items
- .filter(function () {
- return /^\w+$/i.test( letter ) && // not allow modifier keys ( ctrl, cmd, meta, super... )
- new RegExp('^' + letter, 'i').test( $(this).text() ) // find first match
- }),
- nMatches = $matches.length,
- counter = idealSelect.select.data('counter') + 1 || 0,
- curKey = idealSelect.select.data('key') || key,
- newIdx = $matches.eq(counter).index()
- if (!nMatches) // No matches
- return false
- // If more matches with same letter
- if (curKey === key) {
- if (counter < nMatches) {
- idealSelect.select.data('counter', counter)
- }
- else {
- idealSelect.select.data('counter', 0)
- newIdx = $matches.eq(0).index()
- }
- }
- // If new letter
- else {
- idealSelect.select.data('counter', 0)
- newIdx = $matches.eq(0).index()
- }
- if (isOpen)
- Actions.select(newIdx)
- else
- Actions.change(newIdx)
- idealSelect.select.data('key', key)
- Actions.scrollToItem()
- Actions.focusHack()
- }
- }
- keys[key]
- ? keys[key]()
- : keys['default']()
- }
- }
- /**
- * @namespace Holds all events of custom select for "menu mode" and "list mode"
- * @memberOf $.fn.toCustomSelect
- */
- var events = {
- focus: Actions.focus,
- 'blur.menu': function () {
- Actions.blur()
- Actions.hideMenu()
- },
- 'blur.list': function () {
- Actions.blur()
- },
- keydown: function (e) {
- Actions.keydown(e.which)
- },
- 'clickItem.menu': function () {
- Actions.change($(this).index())
- Actions.hideMenu()
- },
- 'clickItem.list': function () {
- Actions.change($(this).index())
- },
- 'clickTitle.menu': function () {
- Actions.focus()
- Actions.showMenu()
- $select.trigger('focus')
- },
- 'hideOutside.menu': function () {
- $select.off('blur.menu')
- $(document).on('mousedown.ideal', function (evt) {
- if (!$(evt.target).closest(idealSelect.select).length) {
- $(document).off('mousedown.ideal')
- $select.on('blur.menu', events['blur.menu'])
- } else {
- Actions.focusHack()
- }
- })
- },
- 'mousedown.list': function () {
- Actions.focusHack()
- }
- }
- // Reset events
- var disableEvents = function () {
- idealSelect.select.removeClass('ideal-select-menu ideal-select-list')
- $select.off('.menu .list')
- idealSelect.items.off('.menu .list')
- idealSelect.select.off('.menu .list')
- idealSelect.title.off('.menu .list')
- }
- // Menu mode
- idealSelect.select.on('menu', function () {
- disableEvents()
- idealSelect.select.addClass('ideal-select-menu')
- Actions.hideMenu()
- $select.on({
- 'blur.menu': events['blur.menu'],
- 'focus.menu': events.focus,
- 'keydown.menu': events.keydown
- })
- idealSelect.select.on('mousedown.menu', events['hideOutside.menu'])
- idealSelect.items.on('click.menu', events['clickItem.menu'])
- idealSelect.title.on('click.menu', events['clickTitle.menu'])
- })
- // List mode
- idealSelect.select.on('list', function () {
- disableEvents()
- idealSelect.select.addClass('ideal-select-list')
- Actions.showMenu()
- $select.on({
- 'blur.list': events['blur.list'],
- 'focus.list': events.focus,
- 'keydown.list': events.keydown
- })
- idealSelect.select.on('mousedown.list', events['mousedown.list'])
- idealSelect.items.on('mousedown.list', events['clickItem.list'])
- })
- $select.keydown(function (e) {
- // Prevent default keydown event
- // to avoid bugs with Ideal Select events
- if (e.which !== 9) e.preventDefault()
- })
- // Reset
- idealSelect.select.on('reset', function(){
- Actions.change(0)
- })
- idealSelect.select.trigger('menu') // Default to "menu mode"
- })
- }
- /*
- * idealRadioCheck: jQuery plguin for checkbox and radio replacement
- * Usage: $('input[type=checkbox], input[type=radio]').idealRadioCheck()
- */
- $.fn.idealRadioCheck = function() {
- return this.each(function() {
- var $this = $(this)
- var $span = $('<span/>')
- $span.addClass( 'ideal-'+ ( $this.is(':checkbox') ? 'check' : 'radio' ) )
- $this.is(':checked') && $span.addClass('checked') // init
- $span.insertAfter( $this )
- $this.parent('label').addClass('ideal-radiocheck-label')
- .attr('onclick', '') // Fix clicking label in iOS
- $this.css({ position: 'absolute', left: '-9999px' }) // hide by shifting left
- // Events
- $this.on({
- change: function() {
- var $this = $(this)
- if ( $this.is('input[type="radio"]') ) {
- $this.parent().siblings('label').find('.ideal-radio').removeClass('checked')
- }
- $span.toggleClass( 'checked', $this.is(':checked') )
- },
- focus: function() { $span.addClass('focus') },
- blur: function() { $span.removeClass('focus') },
- click: function() { $(this).trigger('focus') }
- })
- })
- }
- ;(function( $ ) {
- // Browser supports HTML5 multiple file?
- var multipleSupport = typeof $('<input/>')[0].multiple !== 'undefined',
- isIE = /msie/i.test( navigator.userAgent )
- $.fn.idealFile = function() {
- return this.each(function() {
- var $file = $(this).addClass('ideal-file'), // the original file input
- // label that will be used for IE hack
- $wrap = $('<div class="ideal-file-wrap">'),
- $input = $('<input type="text" class="ideal-file-filename" />'),
- // Button that will be used in non-IE browsers
- $button = $('<button type="button" class="ideal-file-upload">Open</button>'),
- // Hack for IE
- $label = $('<label class="ideal-file-upload" for="'+ $file[0].id +'">Open</label>')
- // Hide by shifting to the left so we
- // can still trigger events
- $file.css({
- position: 'absolute',
- left: '-9999px'
- })
- $wrap.append( $input, ( isIE ? $label : $button ) ).insertAfter( $file )
- // Prevent focus
- $file.attr('tabIndex', -1)
- $button.attr('tabIndex', -1)
- $button.click(function () {
- $file.focus().click() // Open dialog
- })
- $file.change(function() {
- var files = [], fileArr, filename
- // If multiple is supported then extract
- // all filenames from the file array
- if ( multipleSupport ) {
- fileArr = $file[0].files
- for ( var i = 0, len = fileArr.length; i < len; i++ ) {
- files.push( fileArr[i].name )
- }
- filename = files.join(', ')
- // If not supported then just take the value
- // and remove the path to just show the filename
- } else {
- filename = $file.val().split('\\').pop()
- }
- $input.val( filename ) // Set the value
- .attr( 'title', filename ) // Show filename in title tootlip
- })
- $input.on({
- focus: function () { $file.trigger('change') },
- blur: function () { $file.trigger('blur') },
- keydown: function( e ) {
- if ( e.which === 13 ) { // Enter
- if ( !isIE ) { $file.trigger('click') }
- } else if ( e.which === 8 || e.which === 46 ) { // Backspace & Del
- // On some browsers the value is read-only
- // with this trick we remove the old input and add
- // a clean clone with all the original events attached
- $file.replaceWith( $file = $file.val('').clone( true ) )
- $file.trigger('change')
- $input.val('')
- } else if ( e.which === 9 ){ // TAB
- return
- } else { // All other keys
- return false
- }
- }
- })
- })
- }
- }( jQuery ))
- /**
- * @namespace Errors
- * @locale en
- */
- $.idealforms.errors = {
- required: '此处是必填的.',
- number: '必须是数字.',
- digits: '必须是唯一的数字.',
- name: '必须至少有3个字符长,并且只能包含字母.',
- username: '用户名最短5位,最长30位,请使用英文字母、数字、中文和下划线.用户名首字符必须为字母、数字、中文,不能为全数字.中文最长21个字.',
- pass: '密码的位数必须的在6-15位之间,并且至少包含一个数字,一个大写字母和一个小写字母.',
- strongpass: '必须至少为8个字符长,至少包含一个大写字母和一个小写字母和一个数字或特殊字符.',
- email: '必须是一个有效的email地址. <em>(例: user@gmail.com)</em>',
- phone: '必须是一个有效的手机号码. <em>(例: 18723101212)</em>',
- zip: 'Must be a valid US zip code. <em>(e.g. 33245 or 33245-0003)</em>',
- url: 'Must be a valid URL. <em>(e.g. www.google.com)</em>',
- minChar: 'Must be at least <strong>{0}</strong> characters long.',
- minOption: 'Check at least <strong>{0}</strong> options.',
- maxChar: 'No more than <strong>{0}</strong> characters long.',
- maxOption: 'No more than <strong>{0}</strong> options allowed.',
- range: 'Must be a number between {0} and {1}.',
- date: 'Must be a valid date. <em>(e.g. {0})</em>',
- dob: 'Must be a valid date of birth.',
- exclude: '"{0}" is not available.',
- excludeOption: '{0}',
- equalto: 'Must be the same value as <strong>"{0}"</strong>',
- extension: 'File(s) must have a valid extension. <em>(e.g. "{0}")</em>',
- ajaxSuccess: '<strong>{0}</strong> is not available.',
- ajaxError: 'Server error...'
- }
- /**
- * Get all default filters
- * @returns object
- */
- var getFilters = function() {
- var filters = {
- required: {
- regex: /.+/,
- error: $.idealforms.errors.required
- },
- number: {
- regex: function( i, v ) { return !isNaN(v) },
- error: $.idealforms.errors.number
- },
- digits: {
- regex: /^\d+$/,
- error: $.idealforms.errors.digits
- },
- name: {
- regex: /^[A-Za-z]{3,}$/,
- error: $.idealforms.errors.name
- },
- username: {
- regex: /^[a-z](?=[\w.]{4,30}$)\w*\.?\w*$/i,
- error: $.idealforms.errors.username
- },
- pass: {
- regex: /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/,
- error: $.idealforms.errors.pass
- },
- strongpass: {
- regex: /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/,
- error: $.idealforms.errors.strongpass
- },
- email: {
- regex: /^([a-zA-Z0-9]*[-_.]?[a-zA-Z0-9]+)*@([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)+[\\.][A-Za-z]{2,3}([\\.][A-Za-z]{2})?$/,
- error: $.idealforms.errors.email
- },
- phone: {
- //regex: /^((13[0-9])|(15[0-9])|(17[0-9])|(18[0-9]))\\d{8}$/,
- regex: /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/,
- error: $.idealforms.errors.phone
- },
- zip: {
- regex: /^\d{5}$|^\d{5}-\d{4}$/,
- error: $.idealforms.errors.zip
- },
- url: {
- regex: /^(?:(ftp|http|https):\/\/)?(?:[\w\-]+\.)+[a-z]{2,6}([\:\/?#].*)?$/i,
- error: $.idealforms.errors.url
- },
- min: {
- regex: function( input, value ) {
- var $inputinput = input.input,
- min = input.userOptions.data.min,
- isRadioCheck = $input.is('[type="checkbox"], [type="radio"]')
- if ( isRadioCheck ) {
- this.error = $.idealforms.errors.minOption.replace( '{0}', min )
- return $input.filter(':checked').length >= min
- }
- this.error = $.idealforms.errors.minChar.replace( '{0}', min )
- return value.length >= min
- }
- },
- max: {
- regex: function( input, value ) {
- var $inputinput = input.input,
- max = input.userOptions.data.max,
- isRadioCheck = $input.is('[type="checkbox"], [type="radio"]')
- if ( isRadioCheck ) {
- this.error = $.idealforms.errors.maxOption.replace( '{0}', max )
- return $input.filter(':checked').length <= max
- }
- this.error = $.idealforms.errors.maxChar.replace( '{0}', max )
- return value.length <= max
- }
- },
- range: {
- regex: function( input, value ) {
- var range = input.userOptions.data.range,
- val = +value
- this.error = $.idealforms.errors.range
- .replace( '{0}', range[0] )
- .replace( '{1}', range[1] )
- return val >= range[0] && val <= range[1]
- }
- },
- date: {
- regex: function( input, value ) {
- var
- userFormat =
- input.userOptions.data && input.userOptions.data.date
- ? input.userOptions.data.date
- : 'mm/dd/yyyy', // default format
- delimiter = /[^mdy]/.exec( userFormat )[0],
- theFormat = userFormat.split(delimiter),
- theDate = value.split(delimiter),
- isDate = function( date, format ) {
- var m, d, y
- for ( var i = 0, len = format.length; i < len; i++ ) {
- if ( /m/.test( format[i]) ) m = date[i]
- if ( /d/.test( format[i]) ) d = date[i]
- if ( /y/.test( format[i]) ) y = date[i]
- }
- return (
- m > 0 && m < 13 &&
- y && y.length === 4 &&
- d > 0 && d <= ( new Date( y, m, 0 ) ).getDate()
- )
- }
- this.error = $.idealforms.errors.date.replace( '{0}', userFormat )
- return isDate( theDate, theFormat )
- }
- },
- dob: {
- regex: function( input, value ) {
- var
- userFormat =
- input.userOptions.data && input.userOptions.data.dob
- ? input.userOptions.data.dob
- : 'mm/dd/yyyy', // default format
- // Simulate a date input
- dateInput = {
- input: input.input,
- userOptions: {
- data: { date: userFormat }
- }
- },
- // Use internal date filter to validate the date
- isDate = filters.date.regex( dateInput, value ),
- // DOB
- theYear = /\d{4}/.exec( value ),
- maxYear = new Date().getFullYear(), // Current year
- minYear = maxYear - 100
- this.error = $.idealforms.errors.dob
- return isDate && theYear >= minYear && theYear <= maxYear
- }
- },
- exclude: {
- regex: function( input, value ) {
- var $inputinput = input.input,
- exclude = input.userOptions.data.exclude,
- isOption = $input.is('[type="checkbox"], [type="radio"], select')
- this.error = isOption
- ? $.idealforms.errors.excludeOption.replace( '{0}', value )
- : this.error = $.idealforms.errors.exclude.replace( '{0}', value )
- return $.inArray( value, exclude ) === -1
- }
- },
- equalto: {
- regex: function( input, value ) {
- var $equals = $( input.userOptions.data.equalto ),
- $inputinput = input.input,
- name = $equals.attr('name') || $equals.attr('id'),
- isValid = $equals.parents('.ideal-field')
- .filter(function(){ return $(this).data('ideal-isvalid') === true })
- .length
- if ( !isValid ) { return false }
- this.error = $.idealforms.errors.equalto.replace( '{0}', name )
- return $input.val() === $equals.val()
- }
- },
- extension: {
- regex: function( input, value ) {
- var files = input.input[0].files || [{ name: value }],
- extensions = input.userOptions.data.extension,
- re = new RegExp( '\\.'+ extensions.join('|') +'$', 'i' ),
- valid = false
- for ( var i = 0, len = files.length; i < len; i++ ) {
- valid = re.test( files[i].name );
- }
- this.error = $.idealforms.errors.extension.replace( '{0}', extensions.join('", "') )
- return valid
- }
- },
- ajax: {
- regex: function( input, value, showOrHideError ) {
- var self = this
- var $inputinput = input.input
- var userOptions = input.userOptions
- var name = $input.attr('name')
- var $field = $input.parents('.ideal-field')
- var valid = false
- var customErrors = userOptions.errors && userOptions.errors.ajax
- self.error = {}
- self.error.success = customErrors && customErrors.success
- ? customErrors.success
- : $.idealforms.errors.ajaxSuccess.replace( '{0}', value )
- self.error.fail = customErrors && customErrors.error
- ? customErrors.error
- : $.idealforms.errors.ajaxError
- // Send input name as $_POST[name]
- var data = {}
- data[ name ] = $.trim( value )
- // Ajax options defined by the user
- var userAjaxOps = input.userOptions.data.ajax
- var ajaxOps = {
- type: 'post',
- dataType: 'json',
- data: data,
- success: function( resp, text, xhr ) {
- console.log(resp)
- showOrHideError( self.error.success, true )
- $input.data({
- 'ideal-ajax-resp': resp,
- 'ideal-ajax-error': self.error.success
- })
- $input.trigger('change') // to update counter
- $field.removeClass('ajax')
- // Run custom success callback
- if( userAjaxOps._success ) {
- userAjaxOps._success( resp, text, xhr )
- }
- },
- error: function( xhr, text, error ) {
- if ( text !== 'abort' ) {
- showOrHideError( self.error.fail, false )
- $input.data( 'ideal-ajax-error', self.error.fail )
- $field.removeClass('ajax')
- // Run custom error callback
- if ( userAjaxOps._error ) {
- userAjaxOps._error( xhr, text, error )
- }
- }
- }
- }
- $.extend( ajaxOps, userAjaxOps )
- // Init
- $input.removeData('ideal-ajax-error')
- $input.removeData('ideal-ajax-resp')
- $field.addClass('ajax')
- // Run request and save it to be able to abort it
- // so requests don't bubble
- $.idealforms.ajaxRequests[ name ] = $.ajax( ajaxOps )
- }
- }
- }
- return filters
- }
- $.idealforms.flags = {
- noerror: function (i) {
- i.parent().siblings('.ideal-error').hide()
- },
- noicons: function (i) {
- i.siblings('.ideal-icon-valid, .ideal-icon-invalid').hide()
- },
- novalidicon: function (i) {
- i.siblings('.ideal-icon-valid').hide()
- },
- noinvalidicon: function (i) {
- i.siblings('.ideal-icon-invalid').hide()
- },
- noclass: function (i) {
- i.parents('.ideal-field').removeClass('valid invalid')
- },
- novalidclass: function (i) {
- i.parents('.ideal-field').removeClass('valid')
- },
- noinvalidclass: function (i) {
- i.parents('.ideal-field').removeClass('invalid')
- }
- }
- /*
- * Ideal Forms plugin
- */
- var _defaults = {
- inputs: {},
- customFilters: {},
- customFlags: {},
- globalFlags: '',
- onSuccess: function(e) { alert('Thank you...') },
- onFail: function() { alert('Invalid!') },
- responsiveAt: 'auto',
- disableCustom: ''
- }
- // Constructor
- var IdealForms = function( element, options ) {
- var self = this
- self.$form = $( element )
- self.opts = $.extend( {}, _defaults, options )
- self.$tabs = self.$form.find('section')
- // Set localized filters
- $.extend( $.idealforms.filters, getFilters() )
- self._init()
- }
- // Plugin
- $.fn.idealforms = function( options ) {
- return this.each(function() {
- if ( !$.data( this, 'idealforms' ) ) {
- $.data( this, 'idealforms', new IdealForms( this, options ) )
- }
- })
- }
- // Get LESS variables
- var LessVars = {
- fieldWidth: Utils.getLessVar( 'ideal-field-width', 'width' )
- }
- /*
- * Private Methods
- */
- $.extend( IdealForms.prototype, {
- _init: function() {
- var self = this
- var o = self.opts
- var formElements = self._getFormElements()
- self.$form.css( 'visibility', 'visible' )
- .addClass('ideal-form')
- .attr( 'novalidate', 'novalidate' ) // disable HTML5 validation
- // Do markup
- formElements.inputs
- .add( formElements.headings )
- .add( formElements.separators )
- .each(function(){ self._doMarkup( $(this) ) })
- // Generate tabs
- if ( self.$tabs.length ) {
- var $tabContainer = $('<div class="ideal-wrap ideal-tabs ideal-full-width"/>')
- self.$form.prepend( $tabContainer )
- self.$tabs.idealTabs( $tabContainer )
- }
- // Always show datepicker below the input
- if ( jQuery.ui ) {
- $.datepicker._checkOffset = function( a,b,c ) { return b }
- }
- // Add inputs specified by data-ideal
- // to the list of user inputs
- self.$form.find('[data-ideal]').each(function() {
- var userInput = o.inputs[ this.name ]
- o.inputs[ this.name ] = userInput || { filters: $(this).data('ideal') }
- })
- // Responsive
- if ( o.responsiveAt ) {
- $(window).resize(function(){ self._responsive() })
- self._responsive()
- }
- // Form events
- self.$form.on({
- keydown: function( e ) {
- // Prevent submit when pressing enter
- // but exclude textareas
- if ( e.which === 13 && e.target.nodeName !== 'TEXTAREA' ) {
- e.preventDefault()
- }
- },
- submit: function( e ) {
- if ( !self.isValid() ) {
- e.preventDefault()
- o.onFail()
- self.focusFirstInvalid()
- } else {
- o.onSuccess( e )
- }
- }
- })
- self._adjust()
- self._attachEvents()
- self.fresh() // Start fresh
- },
- _getFormElements: function() {
- return {
- inputs: this.$form.find('input, select, textarea, :button'),
- labels: this.$form.find('div > label:first-child'),
- text: this.$form.find('input:not([type="checkbox"], [type="radio"], [type="submit"]), textarea'),
- select: this.$form.find('select'),
- radiocheck: this.$form.find('input[type="radio"], input[type="checkbox"]'),
- buttons: this.$form.find(':button'),
- file: this.$form.find('input[type="file"]'),
- headings: this.$form.find('h1, h2, h3, h4, h5, h6'),
- separators: this.$form.find('hr'),
- hidden: this.$form.find('input:hidden')
- }
- },
- _getUserInputs: function() {
- return this.$form.find('[name="'+ Utils.getKeys( this.opts.inputs ).join('"], [name="') +'"]')
- },
- _getTab: function( nameOrIdx ) {
- var self = this
- var isNumber = !isNaN( nameOrIdx )
- if ( isNumber ) {
- return self.$tabs.eq( nameOrIdx )
- }
- return self.$tabs.filter(function() {
- var re = new RegExp( nameOrIdx, 'i' )
- return re.test( $(this).data('ideal-tabs-content-name') )
- })
- },
- _getCurrentTabIdx: function() {
- return this.$tabs.index( this.$form.find('.ideal-tabs-content:visible') )
- },
- _updateTabsCounter: function() {
- var self = this
- self.$tabs.each(function( i ) {
- var invalid = self.getInvalidInTab( i ).length
- self.$tabs.updateCounter( i, invalid )
- })
- },
- _adjust: function() {
- var self = this
- var o = self.opts
- var formElements = self._getFormElements()
- var curTab = self._getCurrentTabIdx()
- // Autocomplete causes some problems...
- formElements.inputs.attr('autocomplete', 'off')
- // Show tabs to calculate dimensions
- if ( self.$tabs.length ) { self.$tabs.show() }
- // Adjust labels
- var labels = formElements.labels
- labels.removeAttr('style').width( Utils.getMaxWidth( labels ) )
- // Adjust headings and separators
- if ( self.$tabs.length ) {
- this.$tabs.each(function(){
- $( this ).find('.ideal-heading:first').addClass('first-child')
- })
- } else {
- self.$form.find('.ideal-heading:first').addClass('first-child')
- }
- self._setDatepicker()
- // Done calculating hide tabs
- if ( self.$tabs.length ) {
- self.$tabs.hide()
- self.switchTab( curTab )
- }
- },
- _setDatepicker: function() {
- var o = this.opts
- var $datepicker = this.$form.find('input.datepicker')
- if ( jQuery.ui && $datepicker.length ) {
- $datepicker.each(function() {
- var userInput = o.inputs[ this.name ]
- var data = userInput && userInput.data && userInput.data.date
- var format = data ? data.replace( 'yyyy', 'yy' ) : 'mm/dd/yy'
- $(this).datepicker({
- dateFormat: format,
- beforeShow: function( input ) {
- $( input ).addClass('open')
- },
- onChangeMonthYear: function() {
- // Hack to fix IE9 not resizing
- var $this = $(this)
- var w = $this.outerWidth() // cache first!
- setTimeout(function() {
- $this.datepicker('widget').css( 'width', w )
- }, 1)
- },
- onClose: function() { $(this).removeClass('open') }
- })
- })
- // Adjust width
- $datepicker.on('focus keyup', function() {
- var t = $(this), w = t.outerWidth()
- t.datepicker('widget').css( 'width', w )
- })
- $datepicker.parent().siblings('.ideal-error').addClass('hidden')
- }
- },
- _doMarkup: function( $element ) {
- var o = this.opts
- var elementType = Utils.getIdealType( $element )
- // Validation elements
- var $field = $('<span class="ideal-field"/>')
- var $error = $('<span class="ideal-error" />')
- var $valid = $('<i class="ideal-icon ideal-icon-valid" />')
- var $invalid = $('<i class="ideal-icon ideal-icon-invalid"/>')
- .click(function(){
- $(this).parent().find('input:first, textarea, select').focus()
- })
- // Basic markup
- $element.closest('div').addClass('ideal-wrap')
- .children('label:first-child').addClass('ideal-label')
- var idealElements = {
- _defaultInput: function() {
- $element.wrapAll( $field ).after( $valid, $invalid )
- .parent().after( $error )
- },
- text: function() { idealElements._defaultInput() },
- radiocheck: function() {
- // Check if input is already wrapped so we don't
- // wrap radios and checks more than once
- var isWrapped = $element.parents('.ideal-field').length
- if ( !isWrapped ) {
- $element.parent().nextAll().andSelf().wrapAll( $field.addClass('ideal-radiocheck') )
- $element.parents('.ideal-field').append( $valid, $invalid ).after( $error )
- }
- if ( !/radiocheck/.test( o.disableCustom ) ) {
- $element.idealRadioCheck()
- }
- },
- select: function() {
- idealElements._defaultInput()
- if ( !/select/.test( o.disableCustom ) ) {
- $element.idealSelect()
- }
- },
- file: function() {
- idealElements._defaultInput()
- if ( !/file/.test( o.disableCustom ) ) {
- $element.idealFile()
- }
- },
- button: function() {
- if ( !/button/.test( o.disableCustom ) ) {
- $element.addClass('ideal-button')
- }
- },
- hidden: function() {
- $element.closest('div').addClass('ideal-hidden')
- },
- heading: function() {
- $element.closest('div').addClass('ideal-full-width')
- $element.parent().children().wrapAll('<span class="ideal-heading"/>')
- },
- separator: function() {
- $element.closest('div').addClass('ideal-full-width')
- $element.wrapAll('<div class="ideal-separator"/>')
- }
- }
- // Generate markup for current element type
- idealElements[ elementType ] ? idealElements[ elementType ]() : $.noop()
- $error.add( $valid ).add( $invalid ).hide() // Start fresh
- },
- /** Validates an input and shows or hides error and icon
- * @memberOf Actions
- * @param {object} $input jQuery object
- * @param {string} e The JavaScript event
- */
- _validate: function( $input, e ) {
- var self = this
- var o = this.opts
- var userOptions = o.inputs[ $input.attr('name') ]
- var userFilters = userOptions.filters && userOptions.filters.split(/\s/)
- var name = $input.attr('name')
- var value = $input.val()
- var ajaxRequest = $.idealforms.ajaxRequests[ name ]
- var isRadioCheck = $input.is('[type="checkbox"], [type="radio"]')
- var inputData = {
- // If is radio or check validate all inputs related by name
- input: isRadioCheck ? self.$form.find('[name="' + name + '"]') : $input,
- userOptions: userOptions
- }
- // Validation elements
- var $field = $input.parents('.ideal-field')
- var $error = $field.siblings('.ideal-error')
- var $invalid = isRadioCheck
- ? $input.parent().siblings('.ideal-icon-invalid')
- : $input.siblings('.ideal-icon-invalid')
- var $valid = isRadioCheck
- ? $input.parent().siblings('.ideal-icon-valid')
- : $input.siblings('.ideal-icon-valid')
- function resetError() {
- $field.removeClass('valid invalid').removeData('ideal-isvalid')
- $error.add( $invalid ).add( $valid ).hide()
- }
- function showOrHideError( error, valid ) {
- resetError()
- valid ? $valid.show() : $invalid.show()
- $field.addClass( valid ? 'valid' : 'invalid' )
- $field.data( 'ideal-isvalid', valid )
- if ( !valid ) {
- $error.html( error ).toggle( $field.is('.ideal-field-focus') )
- }
- }
- // Prevent validation when typing but not introducing any new characters
- // This is mainly to prevent multiple AJAX requests
- var oldValue = $input.data('ideal-value') || 0
- $input.data( 'ideal-value', value )
- if ( e.type === 'keyup' && value === oldValue ) { return false }
- // Validate
- if ( userFilters ) {
- $.each( userFilters, function( i, filter ) {
- var theFilter = $.idealforms.filters[ filter ]
- var customError = userOptions.errors && userOptions.errors[ filter ]
- var error = ''
- // If field is empty and not required
- if ( !value && filter !== 'required' ) {
- resetError()
- return false
- }
- if ( theFilter ) {
- // Abort and reset ajax if there's a request pending
- if ( e.type === 'keyup' && ajaxRequest ) {
- ajaxRequest.abort()
- $field.removeClass('ajax')
- }
- // AJAX
- if ( filter === 'ajax' ) {
- showOrHideError( error, false ) // set invalid till response comes back
- $error.hide()
- if ( e.type === 'keyup' ) {
- theFilter.regex( inputData, value, showOrHideError ) // runs the ajax callback
- } else {
- var ajaxError = $input.data('ideal-ajax-error')
- if ( ajaxError ) {
- showOrHideError( ajaxError, $input.data('ideal-ajax-resp') || false )
- }
- }
- }
- // All other filters
- else {
- var valid = Utils.isRegex( theFilter.regex ) && theFilter.regex.test( value ) ||
- Utils.isFunction( theFilter.regex ) && theFilter.regex( inputData, value )
- error = customError || theFilter.error // assign error after calling regex()
- showOrHideError( error, valid )
- if ( !valid ) { return false }
- }
- }
- })
- }
- // Reset if there are no filters
- else {
- resetError()
- }
- // Flags
- var flags = (function(){
- var f = userOptions.flags && userOptions.flags.split(' ') || []
- if ( o.globalFlags ) {
- $.each( o.globalFlags.split(' '), function( i,v ) { f.push(v) })
- }
- return f
- }())
- if ( flags.length ) {
- $.each(flags, function( i,f ) {
- var theFlag = $.idealforms.flags[f]
- if ( theFlag ) { theFlag( $input, e.type ) }
- })
- }
- // Update counter
- if ( self.$tabs.length ) {
- self._updateTabsCounter( self._getCurrentTabIdx() )
- }
- },
- _attachEvents: function() {
- var self = this
- self._getUserInputs().on('keyup change focus blur', function(e) {
- var $this = $(this)
- var $field = $this.parents('.ideal-field')
- var isFile = $this.is('input[type=file]')
- // Trigger on change if type=file cuz custom file
- // disables focus on original file input (tabIndex = -1)
- if ( e.type === 'focus' || isFile && e.type === 'change' ) {
- $field.addClass('ideal-field-focus')
- }
- if ( e.type === 'blur' ) {
- $field.removeClass('ideal-field-focus')
- }
- self._validate( $this, e )
- })
- },
- _responsive: function() {
- var formElements = this._getFormElements()
- var maxWidth = LessVars.fieldWidth + formElements.labels.outerWidth()
- var $emptyLabel = formElements.labels.filter(function() {
- return $(this).html() === ' '
- })
- var $customSelect = this.$form.find('.ideal-select')
- this.opts.responsiveAt === 'auto'
- ? this.$form.toggleClass( 'stack', this.$form.width() < maxWidth )
- : this.$form.toggleClass( 'stack', $(window).width() < this.opts.responsiveAt )
- var isStack = this.$form.is('.stack')
- $emptyLabel.toggle( !isStack )
- $customSelect.trigger( isStack ? 'list' : 'menu' )
- // Hide datePicker
- var $datePicker = this.$form.find('input.hasDatepicker')
- if ( $datePicker.length ) { $datePicker.datepicker('hide') }
- }
- })
- /*
- * Public Methods
- */
- $.extend( IdealForms.prototype, {
- getInvalid: function() {
- return this.$form.find('.ideal-field').filter(function() {
- return $(this).data('ideal-isvalid') === false
- })
- },
- getInvalidInTab: function( nameOrIdx ) {
- return this._getTab( nameOrIdx ).find('.ideal-field').filter(function() {
- return $(this).data('ideal-isvalid') === false
- })
- },
- isValid: function() {
- return !this.getInvalid().length
- },
- isValidField: function( field ) {
- var $input = Utils.getByNameOrId( field )
- return $input.parents('.ideal-field').data('ideal-isvalid') === true
- },
- focusFirst: function() {
- if ( this.$tabs.length ) {
- this.$tabs.filter(':visible')
- .find('.ideal-field:first')
- .find('input:first, select, textarea').focus()
- } else {
- this.$form.find('.ideal-field:first')
- .find('input:first, select, textarea').focus()
- }
- return this
- },
- focusFirstInvalid: function() {
- var $first = this.getInvalid().first().find('input:first, select, textarea')
- var tabName = $first.parents('.ideal-tabs-content').data('ideal-tabs-content-name')
- if ( this.$tabs.length ) {
- this.switchTab( tabName )
- }
- $first.focus()
- return this
- },
- switchTab: function( nameOrIdx ) {
- this.$tabs.switchTab( nameOrIdx )
- return this
- },
- nextTab: function() {
- this.$tabs.nextTab()
- return this
- },
- prevTab: function() {
- this.$tabs.prevTab()
- return this
- },
- firstTab: function() {
- this.$tabs.firstTab()
- return this
- },
- lastTab: function() {
- this.$tabs.lastTab()
- return this
- },
- fresh: function() {
- this._getUserInputs().change().parents('.ideal-field')
- .removeClass('valid invalid')
- return this
- },
- freshFields: function( fields ) {
- fields = Utils.convertToArray( fields )
- $.each( fields, function( i ) {
- var $input = Utils.getByNameOrId( fields[ i ] )
- $input.change().parents('.ideal-field').removeClass('valid invalid')
- })
- return this
- },
- reload: function() {
- this._adjust()
- this._attachEvents()
- return this
- },
- reset: function() {
- var formElements = this._getFormElements()
- formElements.text.val('') // text inputs
- formElements.radiocheck.removeAttr('checked') // radio & check
- // Select and custom select
- formElements.select.find('option').first().prop( 'selected', true )
- this.$form.find('.ideal-select').trigger('reset')
- if ( this.$tabs.length ) { this.firstTab() }
- this.focusFirst().fresh()
- return this
- },
- resetFields: function( fields ) {
- fields = Utils.convertToArray( fields )
- var formElements = this._getFormElements()
- $.each( fields, function( i, v ) {
- var $input = Utils.getByNameOrId( v )
- var type = Utils.getIdealType( $input )
- if ( type === 'text' || type === 'file' ) {
- $input.val('')
- }
- if ( type === 'radiocheck' ) {
- $input.removeAttr('checked') // radio & check
- }
- if ( type === 'select' ) {
- $input.find('option').first().prop( 'selected', true )
- $input.next('.ideal-select').trigger('reset')
- }
- $input.change()
- })
- this.freshFields( fields )
- return this
- },
- toggleFields: function( fields ) {
- fields = Utils.convertToArray( fields )
- var self = this
- var $fields = Utils.getFieldsFromArray( fields )
- $fields.each(function() {
- var $this = $(this)
- var name = $this.attr('name') || $this.attr('id')
- var input = self.opts.inputs[ name ]
- var filters = input && input.filters
- var dataFilters = $this.data('ideal-filters') || ''
- $this.data( 'ideal-filters', filters )
- $this.closest('.ideal-wrap').toggle()
- self.setFieldOptions( name, { filters: dataFilters } )
- })
- return this
- },
- setOptions: function( options ) {
- $.extend( true, this.opts, options )
- this.reload().fresh()
- return this
- },
- setFieldOptions: function( name, options ) {
- $.extend( true, this.opts.inputs[ name ], options )
- this.reload().freshFields([ name ])
- return this
- },
- addFields: function( fields ) {
- fields = Utils.convertToArray( fields )
- var self = this
- // Save names of all inputs in Array
- // to use methods that take names ie. fresh()
- var allNames = []
- // Add an input to the DOM
- function add( ops ) {
- var name = ops.name
- var userOptions = {
- filters: ops.filters || '',
- data: ops.data || {},
- errors: ops.errors || {},
- flags: ops.flags || ''
- }
- var label = ops.label || ''
- var type = ops.type
- var list = ops.list || []
- var placeholder = ops.placeholder || ''
- var value = ops.value || ''
- var $field = $('<div>'+
- '<label>'+ label +':</label>'+
- Utils.makeInput( name, value, type, list, placeholder ) +
- '</div>')
- var $input = $field.find('input, select, textarea, :button')
- // Add inputs with filters to the list
- // of user inputs to validate
- if ( userOptions.filters ) { self.opts.inputs[ name ] = userOptions }
- self._doMarkup( $input )
- // Insert in DOM
- if ( ops.addAfter ) {
- $field.insertAfter(
- $( Utils.getByNameOrId( ops.addAfter ) ).parents('.ideal-wrap')
- )
- } else if ( ops.addBefore ) {
- $field.insertBefore(
- $(Utils.getByNameOrId( ops.addBefore ))
- .parents('.ideal-wrap')
- )
- } else if ( ops.appendToTab ) {
- $field.insertAfter(
- self._getTab( ops.appendToTab ).find('.ideal-wrap:last-child')
- )
- } else {
- $field.insertAfter( self.$form.find('.ideal-wrap').last() )
- }
- // Add current field name to list of names
- allNames.push( name )
- }
- // Run through each input
- $.each( fields, function( i, ops ) { add( ops ) })
- self.reload()
- self.freshFields( allNames )
- self._responsive()
- return this
- },
- removeFields: function( fields ) {
- fields = Utils.convertToArray( fields )
- var $fields = Utils.getFieldsFromArray( fields )
- $fields.parents('.ideal-wrap').remove()
- this.reload()
- return this
- }
- })
- }( jQuery, window, document ))
以上所述是本文的全部内容希望对大家有所帮助!
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!
昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。
这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。
而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?
更新日志
- Fine乐团《废墟游乐》[320K/MP3][105.13MB]
- 万山红.2009-花开原野万山红Vol.1-2【柏菲】2CD【WAV+CUE】
- 曾庆瑜1992-18首中英文经典全集[台湾派森][WAV整轨]
- 【上扬爱乐】群星-TheSoundsofLS35AVol.4情迷4【低速原抓WAV分轨】
- Fine乐团《废墟游乐》[Hi-Res][24bit 48kHz][FLAC/分轨][767.04MB]
- Cicada《回返 (十五周年自选集)》[320K/MP3][93.87MB]
- Cicada《回返 (十五周年自选集)》[Hi-Res][24bit 48kHz][FLAC/分轨][466.75MB]
- 郑智化.2024-不思议【智在上作】【FLAC分轨】
- 罗文.2015-NEW.XRCD精丫华星】【WAV+CUE】
- 许秋怡.1995-电影少女【丽音唱片】【FLAC分轨】
- 【中国艺术歌曲典藏】温雅欣《她比烟花寂寞》紫银合金SQCD【低速原抓WAV+CUE】
- 张国荣《FinalEncounter》头版限量编号MQA-UHQ[低速原抓WAV+CUE].
- 发烧萨克斯-雪国之春(SRS+WIZOR)[原抓WAV+CUE]
- 王铮亮《慢人理论》[320K/MP3][175.31MB]
- 王铮亮《慢人理论》[FLAC/分轨][524.11MB]