h5 php登录注册页面验证,H5完成用户注册自动校验的实例详解

/*--------------------------------------------------------------------------

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 = $('

$('.' + 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 ===&nbspnbsp;'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 = '

'type="'+ type +'" '+

'id="'+ name +'" '+

'name="'+ name +'" '+

'value="'+ value +'" '+

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

'/>'

// Textarea

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

markup = ''

}

// 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(''+ item +'')

}

markup =

''+

items.join('') +

''

}

// 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(

''+

''+

item +

''

)

}

markup = items.join('')

}

return markup

}

}

/**

* Custom tabs for Ideal Forms

*/

$.fn.idealTabs = function (container) {

var

// Elements

$contents = this,

$containercontainer = container,

$wrapper = $('

$tabs = (function () {

var tabs = []

$contents.each(function () {

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

var html =

'

'+

'' + name + ''+

'0'+

'

'

tabs.push(html)

})

return $(tabs.join(''))

}()),

getCurIdx: function () {

return $tabs

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

.index()

},

getTabIdxByName: function (name) {

var re =

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

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

})

return $tab.index()

}

},

/**

* Public methods

*/

Methods = {

/**

*/

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 menu jQuery plugin

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

*/

$.fn.idealSelect = function () {

return this.each(function () {

var

$select = $(this),

$options&nbnbsp;= $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 = $('

$menu = $(

'

' +

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

'

'

),

items = (function () {

var items = []

$options.each(function () {

var $this = $(this)

items.push('

' + $this.text() + '')

})

return items

}())

$menu.append('

  • ' + items.join('') + '
')

$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(

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 {

&nnbsp;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.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 $('')[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 = $('

'),

$input = $(''),

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

$button = $('Open'),

// Hack for IE

$label = $('Open')

// 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地址. (例: user@gmail.com)',

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

zip: 'Must be a valid US zip code. (e.g. 33245 or 33245-0003)',

url: 'Must be a valid URL. (e.g. www.google.com)',

minChar: 'Must be at least {0} characters long.',

minOption: 'Check at least {0} options.',

maxChar: 'No more than {0} characters long.',

maxOption: 'No more than {0} options allowed.',

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

date: 'Must be a valid date. (e.g. {0})',

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

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

excludeOption: '{0}',

equalto: 'Must be the same value as "{0}"',

extension: 'File(s) must have a valid extension. (e.g. "{0}")',

ajaxSuccess: '{0} 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 ) {

nbsp;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 = $('

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( nbsp;$(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 = $('')

var $error = $('')

var $valid = $('')

var $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('')

},

separator: function() {

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

$element.wrapAll('

}

}

// 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' ) {

nbsp; 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

&nbspnbsp; 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 = $('

'+

''+ label +':'+

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

'

')

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值