2014-07-17 16:45:12 +02:00
webshims . register ( 'form-shim-extend' , function ( $ , webshims , window , document , undefined , options ) {
"use strict" ;
webshims . inputTypes = webshims . inputTypes || { } ;
//some helper-functions
var cfg = webshims . cfg . forms ;
var bugs = webshims . bugs ;
var splitReg = /\s*,\s*/g ;
var typeModels = webshims . inputTypes ,
checkTypes = {
radio : 1 ,
checkbox : 1
} ,
getType = function ( ) {
var elem = this ;
var type = ( elem . getAttribute ( 'type' ) || '' ) . toLowerCase ( ) ;
return ( webshims . inputTypes [ type ] ) ? type : elem . type ;
} ,
cacheType = function ( cache , input ) {
if ( ! ( 'type' in cache ) ) {
cache . type = getType . call ( input ) ;
}
}
;
( function ( ) {
if ( 'querySelector' in document ) {
try {
bugs . findRequired = ! ( $ ( '<form action="#" style="width: 1px; height: 1px; overflow: hidden;"><select name="b" required="" /></form>' ) [ 0 ] . querySelector ( 'select:required' ) ) ;
} catch ( er ) {
bugs . findRequired = false ;
}
if ( bugs . bustedValidity || bugs . findRequired ) {
( function ( ) {
var find = $ . find ;
var matchesSelector = $ . find . matchesSelector ;
var regExp = /(\:valid|\:invalid|\:optional|\:required)(?=[\s\[\~\.\+\>\:\#*]|$)/ig ;
var regFn = function ( sel ) {
return sel + '-element' ;
} ;
$ . find = ( function ( ) {
var slice = Array . prototype . slice ;
var fn = function ( sel ) {
var ar = arguments ;
ar = slice . call ( ar , 1 , ar . length ) ;
ar . unshift ( sel . replace ( regExp , regFn ) ) ;
return find . apply ( this , ar ) ;
} ;
for ( var i in find ) {
if ( find . hasOwnProperty ( i ) ) {
fn [ i ] = find [ i ] ;
}
}
return fn ;
} ) ( ) ;
$ . find . matchesSelector = function ( node , expr ) {
expr = expr . replace ( regExp , regFn ) ;
return matchesSelector . call ( this , node , expr ) ;
} ;
} ) ( ) ;
}
}
} ) ( ) ;
//API to add new input types
webshims . addInputType = function ( type , obj ) {
typeModels [ type ] = obj ;
} ;
//contsrain-validation-api
var validityPrototype = {
customError : false ,
typeMismatch : false ,
badInput : false ,
rangeUnderflow : false ,
rangeOverflow : false ,
stepMismatch : false ,
tooLong : false ,
tooShort : false ,
patternMismatch : false ,
valueMissing : false ,
valid : true
} ;
var isPlaceholderOptionSelected = function ( select ) {
if ( select . type == 'select-one' && select . size < 2 ) {
var option = $ ( '> option:first-child' , select ) ;
return ! ! option . prop ( 'selected' ) ;
}
return false ;
} ;
var emptyJ = $ ( [ ] ) ;
var getGroupElements = function ( elem ) {
elem = $ ( elem ) ;
var name , form ;
var ret = emptyJ ;
if ( elem [ 0 ] . type == 'radio' ) {
name = elem [ 0 ] . name ;
if ( ! name ) {
ret = elem ;
} else {
form = elem . prop ( 'form' ) ;
ret = $ ( document . getElementsByName ( name ) ) . filter ( function ( ) {
return this . type == 'radio' && $ . prop ( this , 'form' ) == form && this . name == name ;
} ) ;
}
}
return ret ;
} ;
var patternTypes = { url : 1 , email : 1 , text : 1 , search : 1 , tel : 1 , password : 1 } ;
var lengthTypes = $ . extend ( { textarea : 1 } , patternTypes ) ;
var validityRules = {
valueMissing : function ( input , val , cache ) {
if ( ! input . prop ( 'required' ) ) { return false ; }
var ret = false ;
cacheType ( cache , input [ 0 ] ) ;
if ( cache . nodeName == 'select' ) {
ret = ( ! val && ( input [ 0 ] . selectedIndex < 0 || isPlaceholderOptionSelected ( input [ 0 ] ) ) ) ;
} else if ( checkTypes [ cache . type ] ) {
ret = ( cache . type == 'checkbox' ) ? ! input . is ( ':checked' ) : ! getGroupElements ( input ) . filter ( ':checked' ) [ 0 ] ;
} else {
ret = ! ( val ) ;
}
return ret ;
} ,
patternMismatch : function ( input , val , cache ) {
var i ;
var ret = false ;
if ( val === '' || cache . nodeName == 'select' ) { return ret ; }
cacheType ( cache , input [ 0 ] ) ;
if ( ! patternTypes [ cache . type ] ) { return ret ; }
var pattern = input . attr ( 'pattern' ) ;
if ( ! pattern ) { return ret ; }
try {
pattern = new RegExp ( '^(?:' + pattern + ')$' ) ;
} catch ( er ) {
webshims . error ( 'invalid pattern value: "' + pattern + '" | ' + er ) ;
pattern = ret ;
}
if ( ! pattern ) { return ret ; }
val = cache . type == 'email' && input . prop ( 'multiple' ) ? val . split ( splitReg ) : [ val ] ;
for ( i = 0 ; i < val . length ; i ++ ) {
if ( ! pattern . test ( val [ i ] ) ) {
ret = true ;
break ;
}
}
return ret ;
}
}
;
$ . each ( { tooShort : [ 'minLength' , - 1 ] , tooLong : [ 'maxLength' , 1 ] } , function ( name , props ) {
validityRules [ name ] = function ( input , val , cache ) {
//defaultValue is not the same as dirty flag, but very similiar
2014-09-03 00:57:03 +02:00
if ( ! val || cache . nodeName == 'select' || input . prop ( 'defaultValue' ) == val ) { return false ; }
2014-07-17 16:45:12 +02:00
cacheType ( cache , input [ 0 ] ) ;
if ( ! lengthTypes [ cache . type ] ) { return false ; }
var prop = input . prop ( props [ 0 ] ) ;
return ( prop > 0 && prop * props [ 1 ] < val . length * props [ 1 ] ) ;
} ;
} ) ;
$ . each ( { typeMismatch : 'mismatch' , badInput : 'bad' } , function ( name , fn ) {
validityRules [ name ] = function ( input , val , cache ) {
if ( val === '' || cache . nodeName == 'select' ) { return false ; }
var ret = false ;
cacheType ( cache , input [ 0 ] ) ;
if ( typeModels [ cache . type ] && typeModels [ cache . type ] [ fn ] ) {
ret = typeModels [ cache . type ] [ fn ] ( val , input ) ;
} else if ( 'validity' in input [ 0 ] && ( 'name' in input [ 0 ] . validity ) ) {
ret = input [ 0 ] . validity [ name ] || false ;
}
return ret ;
} ;
} ) ;
webshims . modules [ "form-core" ] . getGroupElements = getGroupElements ;
webshims . addValidityRule = function ( type , fn ) {
validityRules [ type ] = fn ;
} ;
$ . event . special . invalid = {
add : function ( ) {
$ . event . special . invalid . setup . call ( this . form || this ) ;
} ,
setup : function ( ) {
var form = this . form || this ;
if ( $ . data ( form , 'invalidEventShim' ) ) {
form = null ;
return ;
}
$ ( form )
. data ( 'invalidEventShim' , true )
. on ( 'submit' , $ . event . special . invalid . handler )
;
webshims . moveToFirstEvent ( form , 'submit' ) ;
if ( webshims . bugs . bustedValidity && $ . nodeName ( form , 'form' ) ) {
( function ( ) {
var noValidate = form . getAttribute ( 'novalidate' ) ;
form . setAttribute ( 'novalidate' , 'novalidate' ) ;
webshims . data ( form , 'bustedNoValidate' , ( noValidate == null ) ? null : noValidate ) ;
} ) ( ) ;
}
form = null ;
} ,
teardown : $ . noop ,
handler : function ( e , d ) {
if ( e . type != 'submit' || e . testedValidity || ! e . originalEvent || ! $ . nodeName ( e . target , 'form' ) || $ . prop ( e . target , 'noValidate' ) ) { return ; }
e . testedValidity = true ;
var notValid = ! ( $ ( e . target ) . callProp ( 'reportValidity' ) ) ;
if ( notValid ) {
e . stopImmediatePropagation ( ) ;
if ( ! options . noFormInvalid ) {
$ ( e . target ) . trigger ( 'invalid' ) ;
}
return false ;
}
}
} ;
$ . event . special . submit = $ . event . special . submit || { setup : function ( ) { return false ; } } ;
var submitSetup = $ . event . special . submit . setup ;
$ . extend ( $ . event . special . submit , {
setup : function ( ) {
if ( $ . nodeName ( this , 'form' ) ) {
$ ( this ) . on ( 'invalid' , $ . noop ) ;
} else {
$ ( 'form' , this ) . on ( 'invalid' , $ . noop ) ;
}
return submitSetup . apply ( this , arguments ) ;
}
} ) ;
webshims . ready ( 'form-shim-extend2 WINDOWLOAD' , function ( ) {
$ ( window ) . on ( 'invalid' , $ . noop ) ;
} ) ;
webshims . addInputType ( 'email' , {
mismatch : ( function ( ) {
//taken from http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address
var test = cfg . emailReg || /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ ;
return function ( val , input ) {
var i ;
var ret = false ;
if ( val ) {
val = input . prop ( 'multiple' ) ? val . split ( splitReg ) : [ val ] ;
for ( i = 0 ; i < val . length ; i ++ ) {
if ( ! test . test ( val [ i ] ) ) {
ret = true ;
break ;
}
}
}
return ret ;
} ;
} ) ( )
} ) ;
webshims . addInputType ( 'url' , {
mismatch : ( function ( ) {
//taken from scott gonzales
var test = cfg . urlReg || /^([a-z]([a-z]|\d|\+|-|\.)*):(\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?((\[(|(v[\da-f]{1,}\.(([a-z]|\d|-|\.|_|~)|[!\$&'\(\)\*\+,;=]|:)+))\])|((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=])*)(:\d*)?)(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*|(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)){0})(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i ;
return function ( val ) {
return val && ! test . test ( val ) ;
} ;
} ) ( )
} ) ;
webshims . defineNodeNameProperty ( 'input' , 'type' , {
prop : {
get : getType
}
} ) ;
// IDLs for constrain validation API
//ToDo: add object to this list
webshims . defineNodeNamesProperties ( [ 'button' , 'fieldset' , 'output' ] , {
checkValidity : {
value : function ( ) { return true ; }
} ,
reportValidity : {
value : function ( ) { return true ; }
} ,
willValidate : {
value : false
} ,
setCustomValidity : {
value : $ . noop
} ,
validity : {
writeable : false ,
get : function ( ) {
return $ . extend ( { } , validityPrototype ) ;
}
}
} , 'prop' ) ;
var baseCheckValidity = function ( elem , type ) {
var e ,
v = $ . prop ( elem , 'validity' )
;
if ( v ) {
$ . data ( elem , 'cachedValidity' , v ) ;
} else {
return true ;
}
if ( ! v . valid ) {
e = $ . Event ( 'invalid' ) ;
var jElm = $ ( elem ) . trigger ( e ) ;
if ( type == 'reportValidity' && ! baseCheckValidity . unhandledInvalids && ! e . isDefaultPrevented ( ) ) {
webshims . validityAlert . showFor ( jElm ) ;
baseCheckValidity . unhandledInvalids = true ;
}
}
$ . removeData ( elem , 'cachedValidity' ) ;
return v . valid ;
} ;
var rsubmittable = /^(?:select|textarea|input)/i ;
[ 'checkValidity' , 'reportValidity' ] . forEach ( function ( name ) {
webshims . defineNodeNameProperty ( 'form' , name , {
prop : {
value : function ( ) {
var ret = true ,
elems = $ ( $ . prop ( this , 'elements' ) ) . filter ( function ( ) {
if ( ! rsubmittable . test ( this . nodeName ) ) { return false ; }
var shadowData = webshims . data ( this , 'shadowData' ) ;
return ! shadowData || ! shadowData . nativeElement || shadowData . nativeElement === this ;
} )
;
baseCheckValidity . unhandledInvalids = false ;
for ( var i = 0 , len = elems . length ; i < len ; i ++ ) {
if ( ! baseCheckValidity ( elems [ i ] , name ) ) {
ret = false ;
}
}
return ret ;
}
}
} ) ;
} ) ;
[ 'input' , 'textarea' , 'select' ] . forEach ( function ( nodeName ) {
var inputValidationAPI = {
setCustomValidity : {
value : function ( error ) {
$ . removeData ( this , 'cachedValidity' ) ;
webshims . data ( this , 'customvalidationMessage' , '' + error ) ;
if ( bugs . bustedValidity && inputValidationAPI . setCustomValidity . prop . _supvalue ) {
inputValidationAPI . setCustomValidity . prop . _supvalue . apply ( this , arguments ) ;
}
}
} ,
willValidate : {
writeable : false ,
get : ( function ( ) {
var types = {
button : 1 ,
reset : 1 ,
hidden : 1 ,
image : 1
}
;
return function ( ) {
var elem = $ ( this ) . getNativeElement ( ) [ 0 ] ;
2014-07-20 02:43:13 +02:00
return ! ! ( ! elem . readOnly && ! types [ elem . type ] && ! $ . find . matchesSelector ( elem , ':disabled' ) ) ;
2014-07-17 16:45:12 +02:00
} ;
} ) ( )
} ,
validity : {
writeable : false ,
get : function ( ) {
var jElm = $ ( this ) . getNativeElement ( ) ;
var elem = jElm [ 0 ] ;
var validityState = $ . data ( elem , 'cachedValidity' ) ;
if ( validityState ) {
return validityState ;
}
validityState = $ . extend ( { } , validityPrototype ) ;
if ( ! $ . prop ( elem , 'willValidate' ) || elem . type == 'submit' ) {
return validityState ;
}
var val = jElm . val ( ) ;
var cache = { nodeName : elem . nodeName . toLowerCase ( ) } ;
validityState . customError = ! ! ( webshims . data ( elem , 'customvalidationMessage' ) ) ;
if ( validityState . customError ) {
validityState . valid = false ;
}
$ . each ( validityRules , function ( rule , fn ) {
if ( fn ( jElm , val , cache ) ) {
validityState [ rule ] = true ;
validityState . valid = false ;
}
} ) ;
$ ( this ) . getShadowFocusElement ( ) . attr ( 'aria-invalid' , validityState . valid ? 'false' : 'true' ) ;
jElm = null ;
elem = null ;
return validityState ;
}
}
} ;
[ 'checkValidity' , 'reportValidity' ] . forEach ( function ( name ) {
inputValidationAPI [ name ] = {
value : function ( ) {
baseCheckValidity . unhandledInvalids = false ;
return baseCheckValidity ( $ ( this ) . getNativeElement ( ) [ 0 ] , name ) ;
}
} ;
} ) ;
webshims . defineNodeNameProperties ( nodeName , inputValidationAPI , 'prop' ) ;
} ) ;
webshims . defineNodeNamesBooleanProperty ( [ 'input' , 'textarea' , 'select' ] , 'required' , {
set : function ( value ) {
$ ( this ) . getShadowFocusElement ( ) . attr ( 'aria-required' , ! ! ( value ) + '' ) ;
} ,
initAttr : true
} ) ;
webshims . defineNodeNamesBooleanProperty ( [ 'input' ] , 'multiple' ) ;
if ( bugs . bustedValidity ) {
webshims . defineNodeNameProperty ( 'form' , 'novalidate' , {
attr : {
set : function ( val ) {
webshims . data ( this , 'bustedNoValidate' , '' + val ) ;
} ,
get : function ( ) {
var ret = webshims . data ( this , 'bustedNoValidate' ) ;
return ret == null ? undefined : ret ;
}
} ,
removeAttr : {
value : function ( ) {
webshims . data ( this , 'bustedNoValidate' , null ) ;
}
}
} ) ;
$ . each ( [ 'rangeUnderflow' , 'rangeOverflow' , 'stepMismatch' ] , function ( i , name ) {
validityRules [ name ] = function ( elem ) {
return ( elem [ 0 ] . validity || { } ) [ name ] || false ;
} ;
} ) ;
}
webshims . defineNodeNameProperty ( 'form' , 'noValidate' , {
prop : {
set : function ( val ) {
val = ! ! val ;
if ( val ) {
$ . attr ( this , 'novalidate' , 'novalidate' ) ;
} else {
$ ( this ) . removeAttr ( 'novalidate' ) ;
}
} ,
get : function ( ) {
return $ . attr ( this , 'novalidate' ) != null ;
}
}
} ) ;
[ 'minlength' , 'minLength' ] . forEach ( function ( propName ) {
webshims . defineNodeNamesProperty ( [ 'input' , 'textarea' ] , propName , {
prop : {
set : function ( val ) {
val *= 1 ;
if ( val < 0 ) {
throw ( 'INDEX_SIZE_ERR' ) ;
}
this . setAttribute ( 'minlength' , val || 0 ) ;
} ,
get : function ( ) {
var val = this . getAttribute ( 'minlength' ) ;
return val == null ? - 1 : ( val * 1 ) || 0 ;
}
}
} ) ;
} ) ;
if ( webshims . support . inputtypes . date && /webkit/i . test ( navigator . userAgent ) ) {
( function ( ) {
var noInputTriggerEvts = { updateInput : 1 , input : 1 } ,
fixInputTypes = {
date : 1 ,
time : 1 ,
month : 1 ,
week : 1 ,
"datetime-local" : 1
} ,
noFocusEvents = {
focusout : 1 ,
blur : 1
} ,
changeEvts = {
updateInput : 1 ,
change : 1
} ,
observe = function ( input ) {
var timer ,
focusedin = true ,
lastInputVal = input . prop ( 'value' ) ,
lastChangeVal = lastInputVal ,
trigger = function ( e ) {
//input === null
if ( ! input ) { return ; }
var newVal = input . prop ( 'value' ) ;
if ( newVal !== lastInputVal ) {
lastInputVal = newVal ;
if ( ! e || ! noInputTriggerEvts [ e . type ] ) {
input . trigger ( 'input' ) ;
}
}
if ( e && changeEvts [ e . type ] ) {
lastChangeVal = newVal ;
}
if ( ! focusedin && newVal !== lastChangeVal ) {
input . trigger ( 'change' ) ;
}
} ,
extraTimer ,
extraTest = function ( ) {
clearTimeout ( extraTimer ) ;
extraTimer = setTimeout ( trigger , 9 ) ;
} ,
unbind = function ( e ) {
clearInterval ( timer ) ;
setTimeout ( function ( ) {
if ( e && noFocusEvents [ e . type ] ) {
focusedin = false ;
}
if ( input ) {
input . off ( 'focusout blur' , unbind ) . off ( 'input change updateInput' , trigger ) ;
trigger ( ) ;
}
input = null ;
} , 1 ) ;
}
;
clearInterval ( timer ) ;
timer = setInterval ( trigger , 160 ) ;
extraTest ( ) ;
input
. off ( {
'focusout blur' : unbind ,
'input change updateInput' : trigger
} )
. on ( {
'focusout blur' : unbind ,
'input updateInput change' : trigger
} )
;
}
;
$ ( document )
. on ( 'focusin' , function ( e ) {
if ( e . target && fixInputTypes [ e . target . type ] && ! e . target . readOnly && ! e . target . disabled ) {
observe ( $ ( e . target ) ) ;
}
} )
;
} ) ( ) ;
}
webshims . addReady ( function ( context , contextElem ) {
//start constrain-validation
2014-11-05 21:25:18 +01:00
2014-07-17 16:45:12 +02:00
$ ( 'form' , context )
. add ( contextElem . filter ( 'form' ) )
. on ( 'invalid' , $ . noop )
;
2014-11-05 21:25:18 +01:00
setTimeout ( function ( ) {
var focusElem ;
try {
if ( ! ( 'form' in ( document . activeElement || { } ) ) ) {
focusElem = $ ( context . querySelector ( 'input[autofocus], select[autofocus], textarea[autofocus]' ) ) . eq ( 0 ) . getShadowFocusElement ( ) [ 0 ] ;
if ( focusElem && ( focusElem . offsetHeight || focusElem . offsetWidth ) ) {
focusElem . focus ( ) ;
}
2014-07-17 16:45:12 +02:00
}
}
2014-11-05 21:25:18 +01:00
catch ( er ) { }
} , 9 ) ;
2014-07-17 16:45:12 +02:00
} ) ;
if ( ! webshims . support . datalist ) {
webshims . defineNodeNameProperty ( 'datalist' , 'options' , {
prop : {
writeable : false ,
get : function ( ) {
var elem = this ;
var select = $ ( 'select' , elem ) ;
var options ;
if ( select [ 0 ] ) {
options = $ . makeArray ( select [ 0 ] . options || [ ] ) ;
} else {
options = elem . getElementsByTagName ( 'option' ) ;
if ( options . length ) {
webshims . warn ( 'you should wrap your option-elements for a datalist in a select element to support IE and other old browsers.' ) ;
}
}
return options ;
}
}
} ) ;
}
var submitterTypes = { submit : 1 , button : 1 , image : 1 } ;
var formSubmitterDescriptors = { } ;
[
{
name : "enctype" ,
limitedTo : {
"application/x-www-form-urlencoded" : 1 ,
"multipart/form-data" : 1 ,
"text/plain" : 1
} ,
defaultProp : "application/x-www-form-urlencoded" ,
proptype : "enum"
} ,
{
name : "method" ,
limitedTo : {
"get" : 1 ,
"post" : 1
} ,
defaultProp : "get" ,
proptype : "enum"
} ,
{
name : "action" ,
proptype : "url"
} ,
{
name : "target"
} ,
{
name : "novalidate" ,
propName : "noValidate" ,
proptype : "boolean"
}
] . forEach ( function ( desc ) {
var propName = 'form' + ( desc . propName || desc . name ) . replace ( /^[a-z]/ , function ( f ) {
return f . toUpperCase ( ) ;
} ) ;
var attrName = 'form' + desc . name ;
var formName = desc . name ;
var eventName = 'click.webshimssubmittermutate' + formName ;
var changeSubmitter = function ( ) {
var elem = this ;
if ( ! ( 'form' in elem ) || ! submitterTypes [ elem . type ] ) { return ; }
var form = $ . prop ( elem , 'form' ) ;
if ( ! form ) { return ; }
var attr = $ . attr ( elem , attrName ) ;
if ( attr != null && ( ! desc . limitedTo || attr . toLowerCase ( ) === $ . prop ( elem , propName ) ) ) {
var oldAttr = $ . attr ( form , formName ) ;
$ . attr ( form , formName , attr ) ;
setTimeout ( function ( ) {
if ( oldAttr != null ) {
$ . attr ( form , formName , oldAttr ) ;
} else {
try {
$ ( form ) . removeAttr ( formName ) ;
} catch ( er ) {
form . removeAttribute ( formName ) ;
}
}
} , 9 ) ;
}
} ;
switch ( desc . proptype ) {
case "url" :
var urlForm = document . createElement ( 'form' ) ;
formSubmitterDescriptors [ propName ] = {
prop : {
set : function ( value ) {
$ . attr ( this , attrName , value ) ;
} ,
get : function ( ) {
var value = $ . attr ( this , attrName ) ;
if ( value == null ) { return '' ; }
urlForm . setAttribute ( 'action' , value ) ;
return urlForm . action ;
}
}
} ;
break ;
case "boolean" :
formSubmitterDescriptors [ propName ] = {
prop : {
set : function ( val ) {
val = ! ! val ;
if ( val ) {
$ . attr ( this , 'formnovalidate' , 'formnovalidate' ) ;
} else {
$ ( this ) . removeAttr ( 'formnovalidate' ) ;
}
} ,
get : function ( ) {
return $ . attr ( this , 'formnovalidate' ) != null ;
}
}
} ;
break ;
case "enum" :
formSubmitterDescriptors [ propName ] = {
prop : {
set : function ( value ) {
$ . attr ( this , attrName , value ) ;
} ,
get : function ( ) {
var value = $ . attr ( this , attrName ) ;
return ( ! value || ( ( value = value . toLowerCase ( ) ) && ! desc . limitedTo [ value ] ) ) ? desc . defaultProp : value ;
}
}
} ;
break ;
default :
formSubmitterDescriptors [ propName ] = {
prop : {
set : function ( value ) {
$ . attr ( this , attrName , value ) ;
} ,
get : function ( ) {
var value = $ . attr ( this , attrName ) ;
return ( value != null ) ? value : "" ;
}
}
} ;
}
if ( ! formSubmitterDescriptors [ attrName ] ) {
formSubmitterDescriptors [ attrName ] = { } ;
}
formSubmitterDescriptors [ attrName ] . attr = {
set : function ( value ) {
formSubmitterDescriptors [ attrName ] . attr . _supset . call ( this , value ) ;
$ ( this ) . off ( eventName ) . on ( eventName , changeSubmitter ) ;
} ,
get : function ( ) {
return formSubmitterDescriptors [ attrName ] . attr . _supget . call ( this ) ;
}
} ;
formSubmitterDescriptors [ attrName ] . initAttr = true ;
formSubmitterDescriptors [ attrName ] . removeAttr = {
value : function ( ) {
$ ( this ) . off ( eventName ) ;
formSubmitterDescriptors [ attrName ] . removeAttr . _supvalue . call ( this ) ;
}
} ;
} ) ;
webshims . defineNodeNamesProperties ( [ 'input' , 'button' ] , formSubmitterDescriptors ) ;
} ) ; //webshims.ready end
; webshims . register ( 'form-message' , function ( $ , webshims , window , document , undefined , options ) {
"use strict" ;
if ( options . lazyCustomMessages ) {
options . customMessages = true ;
}
var validityMessages = webshims . validityMessages ;
var implementProperties = options . customMessages ? [ 'customValidationMessage' ] : [ ] ;
validityMessages . en = $ . extend ( true , {
typeMismatch : {
defaultMessage : 'Please enter a valid value.' ,
email : 'Please enter an email address.' ,
url : 'Please enter a URL.'
} ,
badInput : {
defaultMessage : 'Please enter a valid value.' ,
number : 'Please enter a number.' ,
date : 'Please enter a date.' ,
time : 'Please enter a time.' ,
range : 'Invalid input.' ,
month : 'Please enter a valid value.' ,
"datetime-local" : 'Please enter a datetime.'
} ,
rangeUnderflow : {
defaultMessage : 'Value must be greater than or equal to {%min}.'
} ,
rangeOverflow : {
defaultMessage : 'Value must be less than or equal to {%max}.'
} ,
stepMismatch : 'Invalid input.' ,
tooLong : 'Please enter at most {%maxlength} character(s). You entered {%valueLen}.' ,
tooShort : 'Please enter at least {%minlength} character(s). You entered {%valueLen}.' ,
patternMismatch : 'Invalid input. {%title}' ,
valueMissing : {
defaultMessage : 'Please fill out this field.' ,
checkbox : 'Please check this box if you want to proceed.'
}
} , ( validityMessages . en || validityMessages [ 'en-US' ] || { } ) ) ;
if ( typeof validityMessages [ 'en' ] . valueMissing == 'object' ) {
[ 'select' , 'radio' ] . forEach ( function ( type ) {
validityMessages . en . valueMissing [ type ] = validityMessages . en . valueMissing [ type ] || 'Please select an option.' ;
} ) ;
}
if ( typeof validityMessages . en . rangeUnderflow == 'object' ) {
[ 'date' , 'time' , 'datetime-local' , 'month' ] . forEach ( function ( type ) {
validityMessages . en . rangeUnderflow [ type ] = validityMessages . en . rangeUnderflow [ type ] || 'Value must be at or after {%min}.' ;
} ) ;
}
if ( typeof validityMessages . en . rangeOverflow == 'object' ) {
[ 'date' , 'time' , 'datetime-local' , 'month' ] . forEach ( function ( type ) {
validityMessages . en . rangeOverflow [ type ] = validityMessages . en . rangeOverflow [ type ] || 'Value must be at or before {%max}.' ;
} ) ;
}
if ( ! validityMessages [ 'en-US' ] ) {
validityMessages [ 'en-US' ] = $ . extend ( true , { } , validityMessages . en ) ;
}
if ( ! validityMessages [ 'en-GB' ] ) {
validityMessages [ 'en-GB' ] = $ . extend ( true , { } , validityMessages . en ) ;
}
if ( ! validityMessages [ 'en-AU' ] ) {
validityMessages [ 'en-AU' ] = $ . extend ( true , { } , validityMessages . en ) ;
}
validityMessages [ '' ] = validityMessages [ '' ] || validityMessages [ 'en-US' ] ;
validityMessages . de = $ . extend ( true , {
typeMismatch : {
defaultMessage : '{%value} ist in diesem Feld nicht zulässig.' ,
email : '{%value} ist keine gültige E-Mail-Adresse.' ,
url : '{%value} ist kein(e) gültige(r) Webadresse/Pfad.'
} ,
badInput : {
defaultMessage : 'Geben Sie einen zulässigen Wert ein.' ,
number : 'Geben Sie eine Nummer ein.' ,
date : 'Geben Sie ein Datum ein.' ,
time : 'Geben Sie eine Uhrzeit ein.' ,
month : 'Geben Sie einen Monat mit Jahr ein.' ,
range : 'Geben Sie eine Nummer.' ,
"datetime-local" : 'Geben Sie ein Datum mit Uhrzeit ein.'
} ,
rangeUnderflow : {
defaultMessage : '{%value} ist zu niedrig. {%min} ist der unterste Wert, den Sie benutzen können.'
} ,
rangeOverflow : {
defaultMessage : '{%value} ist zu hoch. {%max} ist der oberste Wert, den Sie benutzen können.'
} ,
stepMismatch : 'Der Wert {%value} ist in diesem Feld nicht zulässig. Hier sind nur bestimmte Werte zulässig. {%title}' ,
tooLong : 'Der eingegebene Text ist zu lang! Sie haben {%valueLen} Zeichen eingegeben, dabei sind {%maxlength} das Maximum.' ,
tooShort : 'Der eingegebene Text ist zu kurz! Sie haben {%valueLen} Zeichen eingegeben, dabei sind {%minlength} das Minimum.' ,
patternMismatch : '{%value} hat für dieses Eingabefeld ein falsches Format. {%title}' ,
valueMissing : {
defaultMessage : 'Bitte geben Sie einen Wert ein.' ,
checkbox : 'Bitte aktivieren Sie das Kästchen.'
}
} , ( validityMessages . de || { } ) ) ;
if ( typeof validityMessages . de . valueMissing == 'object' ) {
[ 'select' , 'radio' ] . forEach ( function ( type ) {
validityMessages . de . valueMissing [ type ] = validityMessages . de . valueMissing [ type ] || 'Bitte wählen Sie eine Option aus.' ;
} ) ;
}
if ( typeof validityMessages . de . rangeUnderflow == 'object' ) {
[ 'date' , 'time' , 'datetime-local' , 'month' ] . forEach ( function ( type ) {
validityMessages . de . rangeUnderflow [ type ] = validityMessages . de . rangeUnderflow [ type ] || '{%value} ist zu früh. {%min} ist die früheste Zeit, die Sie benutzen können.' ;
} ) ;
}
if ( typeof validityMessages . de . rangeOverflow == 'object' ) {
[ 'date' , 'time' , 'datetime-local' , 'month' ] . forEach ( function ( type ) {
validityMessages . de . rangeOverflow [ type ] = validityMessages . de . rangeOverflow [ type ] || '{%value} ist zu spät. {%max} ist die späteste Zeit, die Sie benutzen können.' ;
} ) ;
}
var currentValidationMessage = validityMessages [ '' ] ;
var getMessageFromObj = function ( message , elem ) {
if ( message && typeof message !== 'string' ) {
message = message [ $ . prop ( elem , 'type' ) ] || message [ ( elem . nodeName || '' ) . toLowerCase ( ) ] || message [ 'defaultMessage' ] ;
}
return message || '' ;
} ;
var lReg = /</g ;
var gReg = />/g ;
var valueVals = {
value : 1 ,
min : 1 ,
max : 1
} ;
var toLocale = ( function ( ) {
var monthFormatter ;
var transforms = {
number : function ( val ) {
var num = val * 1 ;
if ( num . toLocaleString && ! isNaN ( num ) ) {
val = num . toLocaleString ( ) || val ;
}
return val ;
}
} ;
var _toLocale = function ( val , elem , attr ) {
var type , widget ;
if ( valueVals [ attr ] ) {
type = $ . prop ( elem , 'type' ) ;
widget = $ ( elem ) . getShadowElement ( ) . data ( 'wsWidget' + type ) ;
if ( widget && widget . formatValue ) {
val = widget . formatValue ( val , false ) ;
} else if ( transforms [ type ] ) {
val = transforms [ type ] ( val ) ;
}
}
return val ;
} ;
[ { n : 'date' , f : 'toLocaleDateString' } , { n : 'time' , f : 'toLocaleTimeString' } , { n : 'datetime-local' , f : 'toLocaleString' } ] . forEach ( function ( desc ) {
transforms [ desc . n ] = function ( val ) {
var date = new Date ( val ) ;
if ( date && date [ desc . f ] ) {
val = date [ desc . f ] ( ) || val ;
}
return val ;
} ;
} ) ;
if ( window . Intl && Intl . DateTimeFormat ) {
monthFormatter = new Intl . DateTimeFormat ( navigator . browserLanguage || navigator . language , { year : "numeric" , month : "2-digit" } ) . format ( new Date ( ) ) ;
if ( monthFormatter && monthFormatter . format ) {
transforms . month = function ( val ) {
var date = new Date ( val ) ;
if ( date ) {
val = monthFormatter . format ( date ) || val ;
}
return val ;
} ;
}
}
webshims . format = { } ;
[ 'date' , 'number' , 'month' , 'time' , 'datetime-local' ] . forEach ( function ( name ) {
webshims . format [ name ] = function ( val , opts ) {
if ( opts && opts . nodeType ) {
return _toLocale ( val , opts , name ) ;
}
if ( name == 'number' && opts && opts . toFixed ) {
val = ( val * 1 ) ;
if ( ! opts . fixOnlyFloat || val % 1 ) {
val = val . toFixed ( opts . toFixed ) ;
}
}
if ( webshims . _format && webshims . _format [ name ] ) {
return webshims . _format [ name ] ( val , opts ) ;
}
return transforms [ name ] ( val ) ;
} ;
} ) ;
return _toLocale ;
} ) ( ) ;
webshims . replaceValidationplaceholder = function ( elem , message , name ) {
var val = $ . prop ( elem , 'title' ) ;
if ( message ) {
if ( name == 'patternMismatch' && ! val ) {
webshims . error ( 'no title for patternMismatch provided. Always add a title attribute.' ) ;
}
if ( val ) {
val = '<span class="ws-titlevalue">' + val . replace ( lReg , '<' ) . replace ( gReg , '>' ) + '</span>' ;
}
if ( message . indexOf ( '{%title}' ) != - 1 ) {
message = message . replace ( '{%title}' , val ) ;
} else if ( val ) {
message = message + ' ' + val ;
}
}
if ( message && message . indexOf ( '{%' ) != - 1 ) {
[ 'value' , 'min' , 'max' , 'maxlength' , 'minlength' , 'label' ] . forEach ( function ( attr ) {
if ( message . indexOf ( '{%' + attr ) === - 1 ) { return ; }
var val = ( ( attr == 'label' ) ? $ . trim ( $ ( 'label[for="' + elem . id + '"]' , elem . form ) . text ( ) ) . replace ( /\*$|:$/ , '' ) : $ . prop ( elem , attr ) || $ . attr ( elem , attr ) || '' ) || '' ;
val = '' + val ;
val = toLocale ( val , elem , attr ) ;
message = message . replace ( '{%' + attr + '}' , val . replace ( lReg , '<' ) . replace ( gReg , '>' ) ) ;
if ( 'value' == attr ) {
message = message . replace ( '{%valueLen}' , val . length ) ;
}
} ) ;
}
return message ;
} ;
webshims . createValidationMessage = function ( elem , name ) {
var message = getMessageFromObj ( currentValidationMessage [ name ] , elem ) ;
if ( ! message && name == 'badInput' ) {
message = getMessageFromObj ( currentValidationMessage . typeMismatch , elem ) ;
}
if ( ! message && name == 'typeMismatch' ) {
message = getMessageFromObj ( currentValidationMessage . badInput , elem ) ;
}
if ( ! message ) {
message = getMessageFromObj ( validityMessages [ '' ] [ name ] , elem ) || $ . prop ( elem , 'validationMessage' ) ;
if ( name != 'customError' ) {
webshims . info ( 'could not find errormessage for: ' + name + ' / ' + $ . prop ( elem , 'type' ) + '. in language: ' + webshims . activeLang ( ) ) ;
}
}
message = webshims . replaceValidationplaceholder ( elem , message , name ) ;
return message || '' ;
} ;
if ( ! webshims . support . formvalidation || webshims . bugs . bustedValidity ) {
implementProperties . push ( 'validationMessage' ) ;
}
currentValidationMessage = webshims . activeLang ( validityMessages ) ;
$ ( validityMessages ) . on ( 'change' , function ( e , data ) {
currentValidationMessage = validityMessages . _ _active ;
} ) ;
implementProperties . forEach ( function ( messageProp ) {
webshims . defineNodeNamesProperty ( [ 'fieldset' , 'output' , 'button' ] , messageProp , {
prop : {
value : '' ,
writeable : false
}
} ) ;
[ 'input' , 'select' , 'textarea' ] . forEach ( function ( nodeName ) {
var desc = webshims . defineNodeNameProperty ( nodeName , messageProp , {
prop : {
get : function ( ) {
var elem = this ;
var message = '' ;
if ( ! $ . prop ( elem , 'willValidate' ) ) {
return message ;
}
var validity = $ . prop ( elem , 'validity' ) || { valid : 1 } ;
if ( validity . valid ) { return message ; }
message = webshims . getContentValidationMessage ( elem , validity ) ;
if ( message ) { return message ; }
if ( validity . customError && elem . nodeName ) {
message = ( webshims . support . formvalidation && ! webshims . bugs . bustedValidity && desc . prop . _supget ) ? desc . prop . _supget . call ( elem ) : webshims . data ( elem , 'customvalidationMessage' ) ;
if ( message ) { return message ; }
}
$ . each ( validity , function ( name , prop ) {
if ( name == 'valid' || ! prop ) { return ; }
message = webshims . createValidationMessage ( elem , name ) ;
if ( message ) {
return false ;
}
} ) ;
return message || '' ;
} ,
writeable : false
}
} ) ;
} ) ;
} ) ;
} ) ;
; webshims . register ( 'form-number-date-api' , function ( $ , webshims , window , document , undefined , options ) {
"use strict" ;
if ( ! webshims . addInputType ) {
webshims . error ( "you can not call forms-ext feature after calling forms feature. call both at once instead: $.webshims.polyfill('forms forms-ext')" ) ;
}
if ( ! webshims . getStep ) {
webshims . getStep = function ( elem , type ) {
var step = $ . attr ( elem , 'step' ) ;
if ( step === 'any' ) {
return step ;
}
type = type || getType ( elem ) ;
if ( ! typeModels [ type ] || ! typeModels [ type ] . step ) {
return step ;
}
step = typeProtos . number . asNumber ( step ) ;
return ( ( ! isNaN ( step ) && step > 0 ) ? step : typeModels [ type ] . step ) * ( typeModels [ type ] . stepScaleFactor || 1 ) ;
} ;
}
if ( ! webshims . addMinMaxNumberToCache ) {
webshims . addMinMaxNumberToCache = function ( attr , elem , cache ) {
if ( ! ( attr + 'AsNumber' in cache ) ) {
cache [ attr + 'AsNumber' ] = typeModels [ cache . type ] . asNumber ( elem . attr ( attr ) ) ;
if ( isNaN ( cache [ attr + 'AsNumber' ] ) && ( attr + 'Default' in typeModels [ cache . type ] ) ) {
cache [ attr + 'AsNumber' ] = typeModels [ cache . type ] [ attr + 'Default' ] ;
}
}
} ;
}
var nan = parseInt ( 'NaN' , 10 ) ,
typeModels = webshims . inputTypes ,
isNumber = function ( string ) {
return ( typeof string == 'number' || ( string && string == string * 1 ) ) ;
} ,
supportsType = function ( type ) {
return ( $ ( '<input type="' + type + '" />' ) . prop ( 'type' ) === type ) ;
} ,
getType = function ( elem ) {
return ( elem . getAttribute ( 'type' ) || '' ) . toLowerCase ( ) ;
} ,
isDateTimePart = function ( string ) {
return ( string && ! ( isNaN ( string * 1 ) ) ) ;
} ,
addMinMaxNumberToCache = webshims . addMinMaxNumberToCache ,
addleadingZero = function ( val , len ) {
val = '' + val ;
len = len - val . length ;
for ( var i = 0 ; i < len ; i ++ ) {
val = '0' + val ;
}
return val ;
} ,
EPS = 1e-7 ,
typeBugs = webshims . bugs . bustedValidity
;
webshims . addValidityRule ( 'stepMismatch' , function ( input , val , cache , validityState ) {
if ( val === '' ) { return false ; }
if ( ! ( 'type' in cache ) ) {
cache . type = getType ( input [ 0 ] ) ;
}
if ( cache . type == 'week' ) { return false ; }
var base , attrVal ;
var ret = ( validityState || { } ) . stepMismatch || false ;
if ( typeModels [ cache . type ] && typeModels [ cache . type ] . step ) {
if ( ! ( 'step' in cache ) ) {
cache . step = webshims . getStep ( input [ 0 ] , cache . type ) ;
}
if ( cache . step == 'any' ) { return false ; }
if ( ! ( 'valueAsNumber' in cache ) ) {
cache . valueAsNumber = typeModels [ cache . type ] . asNumber ( val ) ;
}
if ( isNaN ( cache . valueAsNumber ) ) { return false ; }
addMinMaxNumberToCache ( 'min' , input , cache ) ;
base = cache . minAsNumber ;
if ( isNaN ( base ) && ( attrVal = input . prop ( 'defaultValue' ) ) ) {
base = typeModels [ cache . type ] . asNumber ( attrVal ) ;
}
if ( isNaN ( base ) ) {
base = typeModels [ cache . type ] . stepBase || 0 ;
}
ret = Math . abs ( ( cache . valueAsNumber - base ) % cache . step ) ;
ret = ! ( ret <= EPS || Math . abs ( ret - cache . step ) <= EPS ) ;
}
return ret ;
} ) ;
[ { name : 'rangeOverflow' , attr : 'max' , factor : 1 } , { name : 'rangeUnderflow' , attr : 'min' , factor : - 1 } ] . forEach ( function ( data , i ) {
webshims . addValidityRule ( data . name , function ( input , val , cache , validityState ) {
var ret = ( validityState || { } ) [ data . name ] || false ;
if ( val === '' ) { return ret ; }
if ( ! ( 'type' in cache ) ) {
cache . type = getType ( input [ 0 ] ) ;
}
if ( typeModels [ cache . type ] && typeModels [ cache . type ] . asNumber ) {
if ( ! ( 'valueAsNumber' in cache ) ) {
cache . valueAsNumber = typeModels [ cache . type ] . asNumber ( val ) ;
}
if ( isNaN ( cache . valueAsNumber ) ) {
return false ;
}
addMinMaxNumberToCache ( data . attr , input , cache ) ;
if ( isNaN ( cache [ data . attr + 'AsNumber' ] ) ) {
return ret ;
}
ret = ( cache [ data . attr + 'AsNumber' ] * data . factor < cache . valueAsNumber * data . factor - EPS ) ;
}
return ret ;
} ) ;
} ) ;
webshims . reflectProperties ( [ 'input' ] , [ 'max' , 'min' , 'step' ] ) ;
//IDLs and methods, that aren't part of constrain validation, but strongly tight to it
var valueAsNumberDescriptor = webshims . defineNodeNameProperty ( 'input' , 'valueAsNumber' , {
prop : {
get : function ( ) {
var elem = this ;
var type = getType ( elem ) ;
var ret = ( typeModels [ type ] && typeModels [ type ] . asNumber ) ?
typeModels [ type ] . asNumber ( $ . prop ( elem , 'value' ) ) :
( valueAsNumberDescriptor . prop . _supget && valueAsNumberDescriptor . prop . _supget . apply ( elem , arguments ) ) ;
if ( ret == null ) {
ret = nan ;
}
return ret ;
} ,
set : function ( val ) {
var elem = this ;
var type = getType ( elem ) ;
if ( typeModels [ type ] && typeModels [ type ] . numberToString ) {
//is NaN a number?
if ( isNaN ( val ) ) {
$ . prop ( elem , 'value' , '' ) ;
return ;
}
var set = typeModels [ type ] . numberToString ( val ) ;
if ( set !== false ) {
$ . prop ( elem , 'value' , set ) ;
} else {
webshims . error ( 'INVALID_STATE_ERR: DOM Exception 11' ) ;
}
} else if ( valueAsNumberDescriptor . prop . _supset ) {
valueAsNumberDescriptor . prop . _supset . apply ( elem , arguments ) ;
}
}
}
} ) ;
var valueAsDateDescriptor = webshims . defineNodeNameProperty ( 'input' , 'valueAsDate' , {
prop : {
get : function ( ) {
var elem = this ;
var type = getType ( elem ) ;
return ( typeModels [ type ] && typeModels [ type ] . asDate && ! typeModels [ type ] . noAsDate ) ?
typeModels [ type ] . asDate ( $ . prop ( elem , 'value' ) ) :
valueAsDateDescriptor . prop . _supget && valueAsDateDescriptor . prop . _supget . call ( elem ) || null ;
} ,
set : function ( value ) {
var elem = this ;
var type = getType ( elem ) ;
if ( typeModels [ type ] && typeModels [ type ] . dateToString && ! typeModels [ type ] . noAsDate ) {
if ( value === null ) {
$ . prop ( elem , 'value' , '' ) ;
return '' ;
}
var set = typeModels [ type ] . dateToString ( value ) ;
if ( set !== false ) {
$ . prop ( elem , 'value' , set ) ;
return set ;
} else {
webshims . error ( 'INVALID_STATE_ERR: DOM Exception 11' ) ;
}
} else {
return valueAsDateDescriptor . prop . _supset && valueAsDateDescriptor . prop . _supset . apply ( elem , arguments ) || null ;
}
}
}
} ) ;
$ . each ( { stepUp : 1 , stepDown : - 1 } , function ( name , stepFactor ) {
var stepDescriptor = webshims . defineNodeNameProperty ( 'input' , name , {
prop : {
value : function ( factor ) {
var step , val , valModStep , alignValue , cache , base , attrVal ;
var type = getType ( this ) ;
if ( typeModels [ type ] && typeModels [ type ] . asNumber ) {
cache = { type : type } ;
if ( ! factor ) {
factor = 1 ;
webshims . warn ( "you should always use a factor for stepUp/stepDown" ) ;
}
factor *= stepFactor ;
step = webshims . getStep ( this , type ) ;
if ( step == 'any' ) {
webshims . info ( "step is 'any' can't apply stepUp/stepDown" ) ;
throw ( 'invalid state error' ) ;
}
webshims . addMinMaxNumberToCache ( 'min' , $ ( this ) , cache ) ;
webshims . addMinMaxNumberToCache ( 'max' , $ ( this ) , cache ) ;
val = $ . prop ( this , 'valueAsNumber' ) ;
if ( factor > 0 && ! isNaN ( cache . minAsNumber ) && ( isNaN ( val ) || cache . minAsNumber > val ) ) {
$ . prop ( this , 'valueAsNumber' , cache . minAsNumber ) ;
return ;
} else if ( factor < 0 && ! isNaN ( cache . maxAsNumber ) && ( isNaN ( val ) || cache . maxAsNumber < val ) ) {
$ . prop ( this , 'valueAsNumber' , cache . maxAsNumber ) ;
return ;
}
if ( isNaN ( val ) ) {
val = 0 ;
}
base = cache . minAsNumber ;
if ( isNaN ( base ) && ( attrVal = $ . prop ( this , 'defaultValue' ) ) ) {
base = typeModels [ type ] . asNumber ( attrVal ) ;
}
if ( ! base ) {
base = 0 ;
}
step *= factor ;
val = ( val + step ) . toFixed ( 5 ) * 1 ;
valModStep = ( val - base ) % step ;
if ( valModStep && ( Math . abs ( valModStep ) > EPS ) ) {
alignValue = val - valModStep ;
alignValue += ( valModStep > 0 ) ? step : ( - step ) ;
val = alignValue . toFixed ( 5 ) * 1 ;
}
if ( ( ! isNaN ( cache . maxAsNumber ) && val > cache . maxAsNumber ) || ( ! isNaN ( cache . minAsNumber ) && val < cache . minAsNumber ) ) {
webshims . info ( "max/min overflow can't apply stepUp/stepDown" ) ;
return ;
}
$ . prop ( this , 'valueAsNumber' , val ) ;
} else if ( stepDescriptor . prop && stepDescriptor . prop . _supvalue ) {
return stepDescriptor . prop . _supvalue . apply ( this , arguments ) ;
} else {
webshims . info ( "no step method for type: " + type ) ;
throw ( 'invalid state error' ) ;
}
}
}
} ) ;
} ) ;
/ *
* ToDO : WEEK
* /
// var getWeek = function(date){
// var time;
// var checkDate = new Date(date.getTime());
//
// checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
//
// time = checkDate.getTime();
// checkDate.setMonth(0);
// checkDate.setDate(1);
// return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
// };
//
// var setWeek = function(year, week){
// var date = new Date(year, 0, 1);
//
// week = (week - 1) * 86400000 * 7;
// date = new Date(date.getTime() + week);
// date.setDate(date.getDate() + 1 - (date.getDay() || 7));
// return date;
// };
var typeProtos = {
number : {
bad : function ( val ) {
return ! ( isNumber ( val ) ) ;
} ,
step : 1 ,
//stepBase: 0, 0 = default
stepScaleFactor : 1 ,
asNumber : function ( str ) {
return ( isNumber ( str ) ) ? str * 1 : nan ;
} ,
numberToString : function ( num ) {
return ( isNumber ( num ) ) ? num : false ;
}
} ,
range : {
minDefault : 0 ,
maxDefault : 100
} ,
color : {
bad : ( function ( ) {
var cReg = /^\u0023[a-f0-9]{6}$/ ;
return function ( val ) {
return ( ! val || val . length != 7 || ! ( cReg . test ( val ) ) ) ;
} ;
} ) ( )
} ,
date : {
bad : function ( val ) {
if ( ! val || ! val . split || ! ( /\d$/ . test ( val ) ) ) { return true ; }
var i ;
var valA = val . split ( /\u002D/ ) ;
if ( valA . length !== 3 ) { return true ; }
var ret = false ;
if ( valA [ 0 ] . length < 4 || valA [ 1 ] . length != 2 || valA [ 1 ] > 12 || valA [ 2 ] . length != 2 || valA [ 2 ] > 33 ) {
ret = true ;
} else {
for ( i = 0 ; i < 3 ; i ++ ) {
if ( ! isDateTimePart ( valA [ i ] ) ) {
ret = true ;
break ;
}
}
}
return ret || ( val !== this . dateToString ( this . asDate ( val , true ) ) ) ;
} ,
step : 1 ,
//stepBase: 0, 0 = default
stepScaleFactor : 86400000 ,
asDate : function ( val , _noMismatch ) {
if ( ! _noMismatch && this . bad ( val ) ) {
return null ;
}
return new Date ( this . asNumber ( val , true ) ) ;
} ,
asNumber : function ( str , _noMismatch ) {
var ret = nan ;
if ( _noMismatch || ! this . bad ( str ) ) {
str = str . split ( /\u002D/ ) ;
ret = Date . UTC ( str [ 0 ] , str [ 1 ] - 1 , str [ 2 ] ) ;
}
return ret ;
} ,
numberToString : function ( num ) {
return ( isNumber ( num ) ) ? this . dateToString ( new Date ( num * 1 ) ) : false ;
} ,
dateToString : function ( date ) {
return ( date && date . getFullYear ) ? addleadingZero ( date . getUTCFullYear ( ) , 4 ) + '-' + addleadingZero ( date . getUTCMonth ( ) + 1 , 2 ) + '-' + addleadingZero ( date . getUTCDate ( ) , 2 ) : false ;
}
} ,
/ *
* ToDO : WEEK
* /
// week: {
// bad: function(val){
// if(!val || !val.split){return true;}
// var valA = val.split('-W');
// var ret = true;
// if(valA.length == 2 && valA[0].length > 3 && valA.length == 2){
// ret = this.dateToString(setWeek(valA[0], valA[1])) != val;
// }
// return ret;
// },
// step: 1,
// stepScaleFactor: 604800000,
// stepBase: -259200000,
// asDate: function(str, _noMismatch){
// var ret = null;
// if(_noMismatch || !this.bad(str)){
// ret = str.split('-W');
// ret = setWeek(ret[0], ret[1]);
// }
// return ret;
// },
// asNumber: function(str, _noMismatch){
// var ret = nan;
// var date = this.asDate(str, _noMismatch);
// if(date && date.getUTCFullYear){
// ret = date.getTime();
// }
// return ret;
// },
// dateToString: function(date){
// var week, checkDate;
// var ret = false;
// if(date && date.getFullYear){
// week = getWeek(date);
// if(week == 1){
// checkDate = new Date(date.getTime());
// checkDate.setDate(checkDate.getDate() + 7);
// date.setUTCFullYear(checkDate.getUTCFullYear());
// }
// ret = addleadingZero(date.getUTCFullYear(), 4) +'-W'+addleadingZero(week, 2);
// }
// return ret;
// },
// numberToString: function(num){
// return (isNumber(num)) ? this.dateToString(new Date( num * 1)) : false;
// }
// },
time : {
bad : function ( val , _getParsed ) {
if ( ! val || ! val . split || ! ( /\d$/ . test ( val ) ) ) { return true ; }
val = val . split ( /\u003A/ ) ;
if ( val . length < 2 || val . length > 3 ) { return true ; }
var ret = false ,
sFraction ;
if ( val [ 2 ] ) {
val [ 2 ] = val [ 2 ] . split ( /\u002E/ ) ;
sFraction = parseInt ( val [ 2 ] [ 1 ] , 10 ) ;
val [ 2 ] = val [ 2 ] [ 0 ] ;
}
$ . each ( val , function ( i , part ) {
if ( ! isDateTimePart ( part ) || part . length !== 2 ) {
ret = true ;
return false ;
}
} ) ;
if ( ret ) { return true ; }
if ( val [ 0 ] > 23 || val [ 0 ] < 0 || val [ 1 ] > 59 || val [ 1 ] < 0 ) {
return true ;
}
if ( val [ 2 ] && ( val [ 2 ] > 59 || val [ 2 ] < 0 ) ) {
return true ;
}
if ( sFraction && isNaN ( sFraction ) ) {
return true ;
}
if ( sFraction ) {
if ( sFraction < 100 ) {
sFraction *= 100 ;
} else if ( sFraction < 10 ) {
sFraction *= 10 ;
}
}
return ( _getParsed === true ) ? [ val , sFraction ] : false ;
} ,
step : 60 ,
stepBase : 0 ,
stepScaleFactor : 1000 ,
asDate : function ( val ) {
val = new Date ( this . asNumber ( val ) ) ;
return ( isNaN ( val ) ) ? null : val ;
} ,
asNumber : function ( val ) {
var ret = nan ;
val = this . bad ( val , true ) ;
if ( val !== true ) {
ret = Date . UTC ( '1970' , 0 , 1 , val [ 0 ] [ 0 ] , val [ 0 ] [ 1 ] , val [ 0 ] [ 2 ] || 0 ) ;
if ( val [ 1 ] ) {
ret += val [ 1 ] ;
}
}
return ret ;
} ,
dateToString : function ( date ) {
if ( date && date . getUTCHours ) {
var str = addleadingZero ( date . getUTCHours ( ) , 2 ) + ':' + addleadingZero ( date . getUTCMinutes ( ) , 2 ) ,
tmp = date . getSeconds ( )
;
if ( tmp != "0" ) {
str += ':' + addleadingZero ( tmp , 2 ) ;
}
tmp = date . getUTCMilliseconds ( ) ;
if ( tmp != "0" ) {
str += '.' + addleadingZero ( tmp , 3 ) ;
}
return str ;
} else {
return false ;
}
}
} ,
month : {
bad : function ( val ) {
return typeProtos . date . bad ( val + '-01' ) ;
} ,
step : 1 ,
stepScaleFactor : false ,
//stepBase: 0, 0 = default
asDate : function ( val ) {
return new Date ( typeProtos . date . asNumber ( val + '-01' ) ) ;
} ,
asNumber : function ( val ) {
//1970-01
var ret = nan ;
if ( val && ! this . bad ( val ) ) {
val = val . split ( /\u002D/ ) ;
val [ 0 ] = ( val [ 0 ] * 1 ) - 1970 ;
val [ 1 ] = ( val [ 1 ] * 1 ) - 1 ;
ret = ( val [ 0 ] * 12 ) + val [ 1 ] ;
}
return ret ;
} ,
numberToString : function ( num ) {
var mod ;
var ret = false ;
if ( isNumber ( num ) ) {
mod = ( num % 12 ) ;
num = ( ( num - mod ) / 12 ) + 1970 ;
mod += 1 ;
if ( mod < 1 ) {
num -= 1 ;
mod += 12 ;
}
ret = addleadingZero ( num , 4 ) + '-' + addleadingZero ( mod , 2 ) ;
}
return ret ;
} ,
dateToString : function ( date ) {
if ( date && date . getUTCHours ) {
var str = typeProtos . date . dateToString ( date ) ;
return ( str . split && ( str = str . split ( /\u002D/ ) ) ) ? str [ 0 ] + '-' + str [ 1 ] : false ;
} else {
return false ;
}
}
}
, 'datetime-local' : {
bad : function ( val , _getParsed ) {
if ( ! val || ! val . split || ( val + 'special' ) . split ( /\u0054/ ) . length !== 2 ) { return true ; }
val = val . split ( /\u0054/ ) ;
return ( typeProtos . date . bad ( val [ 0 ] ) || typeProtos . time . bad ( val [ 1 ] , _getParsed ) ) ;
} ,
noAsDate : true ,
asDate : function ( val ) {
val = new Date ( this . asNumber ( val ) ) ;
return ( isNaN ( val ) ) ? null : val ;
} ,
asNumber : function ( val ) {
var ret = nan ;
var time = this . bad ( val , true ) ;
if ( time !== true ) {
val = val . split ( /\u0054/ ) [ 0 ] . split ( /\u002D/ ) ;
ret = Date . UTC ( val [ 0 ] , val [ 1 ] - 1 , val [ 2 ] , time [ 0 ] [ 0 ] , time [ 0 ] [ 1 ] , time [ 0 ] [ 2 ] || 0 ) ;
if ( time [ 1 ] ) {
ret += time [ 1 ] ;
}
}
return ret ;
} ,
dateToString : function ( date , _getParsed ) {
return typeProtos . date . dateToString ( date ) + 'T' + typeProtos . time . dateToString ( date , _getParsed ) ;
}
}
} ;
if ( typeBugs || ! supportsType ( 'range' ) || ! supportsType ( 'time' ) || ! supportsType ( 'month' ) || ! supportsType ( 'datetime-local' ) ) {
typeProtos . range = $ . extend ( { } , typeProtos . number , typeProtos . range ) ;
typeProtos . time = $ . extend ( { } , typeProtos . date , typeProtos . time ) ;
typeProtos . month = $ . extend ( { } , typeProtos . date , typeProtos . month ) ;
typeProtos [ 'datetime-local' ] = $ . extend ( { } , typeProtos . date , typeProtos . time , typeProtos [ 'datetime-local' ] ) ;
}
//
[ 'number' , 'month' , 'range' , 'date' , 'time' , 'color' , 'datetime-local' ] . forEach ( function ( type ) {
if ( typeBugs || ! supportsType ( type ) ) {
webshims . addInputType ( type , typeProtos [ type ] ) ;
}
} ) ;
if ( $ ( '<input />' ) . prop ( 'labels' ) == null ) {
webshims . defineNodeNamesProperty ( 'button, input, keygen, meter, output, progress, select, textarea' , 'labels' , {
prop : {
get : function ( ) {
if ( this . type == 'hidden' ) { return null ; }
var id = this . id ;
var labels = $ ( this )
. closest ( 'label' )
. filter ( function ( ) {
var hFor = ( this . attributes [ 'for' ] || { } ) ;
return ( ! hFor . specified || hFor . value == id ) ;
} )
;
if ( id ) {
labels = labels . add ( 'label[for="' + id + '"]' ) ;
}
return labels . get ( ) ;
} ,
writeable : false
}
} ) ;
}
} ) ;
; webshims . register ( 'form-datalist' , function ( $ , webshims , window , document , undefined , options ) {
"use strict" ;
var lazyLoad = function ( name ) {
if ( ! name || typeof name != 'string' ) {
name = 'DOM' ;
}
if ( ! lazyLoad [ name + 'Loaded' ] ) {
lazyLoad [ name + 'Loaded' ] = true ;
webshims . ready ( name , function ( ) {
webshims . loader . loadList ( [ 'form-datalist-lazy' ] ) ;
} ) ;
}
} ;
var noDatalistSupport = {
submit : 1 ,
button : 1 ,
reset : 1 ,
hidden : 1 ,
range : 1 ,
date : 1 ,
month : 1
} ;
if ( webshims . modules [ "form-number-date-ui" ] . loaded ) {
$ . extend ( noDatalistSupport , {
number : 1 ,
time : 1
} ) ;
}
/ *
* implement propType "element" currently only used for list - attribute ( will be moved to dom - extend , if needed )
* /
webshims . propTypes . element = function ( descs , name ) {
webshims . createPropDefault ( descs , 'attr' ) ;
if ( descs . prop ) { return ; }
descs . prop = {
get : function ( ) {
var elem = $ . attr ( this , name ) ;
if ( elem ) {
elem = document . getElementById ( elem ) ;
if ( elem && descs . propNodeName && ! $ . nodeName ( elem , descs . propNodeName ) ) {
elem = null ;
}
}
return elem || null ;
} ,
writeable : false
} ;
} ;
/ *
* Implements datalist element and list attribute
* /
( function ( ) {
var formsCFG = webshims . cfg . forms ;
var listSupport = webshims . support . datalist ;
if ( listSupport && ! formsCFG . customDatalist ) { return ; }
var initializeDatalist = function ( ) {
var updateDatlistAndOptions = function ( ) {
var id ;
if ( ! $ . data ( this , 'datalistWidgetData' ) && ( id = $ . prop ( this , 'id' ) ) ) {
$ ( 'input[list="' + id + '"], input[data-wslist="' + id + '"]' ) . eq ( 0 ) . attr ( 'list' , id ) ;
} else {
$ ( this ) . triggerHandler ( 'updateDatalist' ) ;
}
} ;
var inputListProto = {
//override autocomplete
autocomplete : {
attr : {
get : function ( ) {
var elem = this ;
var data = $ . data ( elem , 'datalistWidget' ) ;
if ( data ) {
return data . _autocomplete ;
}
return ( 'autocomplete' in elem ) ? elem . autocomplete : elem . getAttribute ( 'autocomplete' ) ;
} ,
set : function ( value ) {
var elem = this ;
var data = $ . data ( elem , 'datalistWidget' ) ;
if ( data ) {
data . _autocomplete = value ;
if ( value == 'off' ) {
data . hideList ( ) ;
}
} else {
if ( 'autocomplete' in elem ) {
elem . autocomplete = value ;
} else {
elem . setAttribute ( 'autocomplete' , value ) ;
}
}
}
}
}
} ;
if ( listSupport ) {
//options only return options, if option-elements are rooted: but this makes this part of HTML5 less backwards compatible
if ( ! ( $ ( '<datalist><select><option></option></select></datalist>' ) . prop ( 'options' ) || [ ] ) . length ) {
webshims . defineNodeNameProperty ( 'datalist' , 'options' , {
prop : {
writeable : false ,
get : function ( ) {
var options = this . options || [ ] ;
if ( ! options . length ) {
var elem = this ;
var select = $ ( 'select' , elem ) ;
if ( select [ 0 ] && select [ 0 ] . options && select [ 0 ] . options . length ) {
options = select [ 0 ] . options ;
}
}
return options ;
}
}
} ) ;
}
inputListProto . list = {
attr : {
get : function ( ) {
var val = webshims . contentAttr ( this , 'list' ) ;
if ( val != null ) {
$ . data ( this , 'datalistListAttr' , val ) ;
if ( ! noDatalistSupport [ $ . prop ( this , 'type' ) ] && ! noDatalistSupport [ $ . attr ( this , 'type' ) ] ) {
this . removeAttribute ( 'list' ) ;
}
} else {
val = $ . data ( this , 'datalistListAttr' ) ;
}
return ( val == null ) ? undefined : val ;
} ,
set : function ( value ) {
var elem = this ;
$ . data ( elem , 'datalistListAttr' , value ) ;
if ( ! noDatalistSupport [ $ . prop ( this , 'type' ) ] && ! noDatalistSupport [ $ . attr ( this , 'type' ) ] ) {
webshims . objectCreate ( shadowListProto , undefined , {
input : elem ,
id : value ,
datalist : $ . prop ( elem , 'list' )
} ) ;
elem . setAttribute ( 'data-wslist' , value ) ;
} else {
elem . setAttribute ( 'list' , value ) ;
}
$ ( elem ) . triggerHandler ( 'listdatalistchange' ) ;
}
} ,
initAttr : true ,
reflect : true ,
propType : 'element' ,
propNodeName : 'datalist'
} ;
} else {
webshims . defineNodeNameProperties ( 'input' , {
list : {
attr : {
get : function ( ) {
var val = webshims . contentAttr ( this , 'list' ) ;
return ( val == null ) ? undefined : val ;
} ,
set : function ( value ) {
var elem = this ;
webshims . contentAttr ( elem , 'list' , value ) ;
webshims . objectCreate ( options . shadowListProto , undefined , { input : elem , id : value , datalist : $ . prop ( elem , 'list' ) } ) ;
$ ( elem ) . triggerHandler ( 'listdatalistchange' ) ;
}
} ,
initAttr : true ,
reflect : true ,
propType : 'element' ,
propNodeName : 'datalist'
}
} ) ;
}
webshims . defineNodeNameProperties ( 'input' , inputListProto ) ;
webshims . addReady ( function ( context , contextElem ) {
contextElem
. filter ( 'datalist > select, datalist, datalist > option, datalist > select > option' )
. closest ( 'datalist' )
. each ( updateDatlistAndOptions )
;
} ) ;
} ;
/ *
* ShadowList
* /
var shadowListProto = {
_create : function ( opts ) {
if ( noDatalistSupport [ $ . prop ( opts . input , 'type' ) ] || noDatalistSupport [ $ . attr ( opts . input , 'type' ) ] ) { return ; }
var datalist = opts . datalist ;
var data = $ . data ( opts . input , 'datalistWidget' ) ;
var that = this ;
if ( datalist && data && data . datalist !== datalist ) {
data . datalist = datalist ;
data . id = opts . id ;
$ ( data . datalist )
. off ( 'updateDatalist.datalistWidget' )
. on ( 'updateDatalist.datalistWidget' , $ . proxy ( data , '_resetListCached' ) )
;
data . _resetListCached ( ) ;
return ;
} else if ( ! datalist ) {
if ( data ) {
data . destroy ( ) ;
}
return ;
} else if ( data && data . datalist === datalist ) {
return ;
}
this . datalist = datalist ;
this . id = opts . id ;
this . hasViewableData = true ;
this . _autocomplete = $ . attr ( opts . input , 'autocomplete' ) ;
$ . data ( opts . input , 'datalistWidget' , this ) ;
$ . data ( datalist , 'datalistWidgetData' , this ) ;
lazyLoad ( 'WINDOWLOAD' ) ;
if ( webshims . isReady ( 'form-datalist-lazy' ) ) {
if ( window . QUnit ) {
that . _lazyCreate ( opts ) ;
} else {
setTimeout ( function ( ) {
that . _lazyCreate ( opts ) ;
} , 9 ) ;
}
} else {
$ ( opts . input ) . one ( 'focus' , lazyLoad ) ;
webshims . ready ( 'form-datalist-lazy' , function ( ) {
if ( ! that . _destroyed ) {
that . _lazyCreate ( opts ) ;
}
} ) ;
}
} ,
destroy : function ( e ) {
var input ;
var autocomplete = $ . attr ( this . input , 'autocomplete' ) ;
$ ( this . input )
. off ( '.datalistWidget' )
. removeData ( 'datalistWidget' )
;
this . shadowList . remove ( ) ;
$ ( document ) . off ( '.datalist' + this . id ) ;
$ ( window ) . off ( '.datalist' + this . id ) ;
if ( this . input . form && this . input . id ) {
$ ( this . input . form ) . off ( 'submit.datalistWidget' + this . input . id ) ;
}
this . input . removeAttribute ( 'aria-haspopup' ) ;
if ( autocomplete === undefined ) {
this . input . removeAttribute ( 'autocomplete' ) ;
} else {
$ ( this . input ) . attr ( 'autocomplete' , autocomplete ) ;
}
if ( e && e . type == 'beforeunload' ) {
input = this . input ;
setTimeout ( function ( ) {
$ . attr ( input , 'list' , $ . attr ( input , 'list' ) ) ;
} , 9 ) ;
}
this . _destroyed = true ;
}
} ;
webshims . loader . addModule ( 'form-datalist-lazy' , {
noAutoCallback : true ,
options : $ . extend ( options , { shadowListProto : shadowListProto } )
} ) ;
if ( ! options . list ) {
options . list = { } ;
}
//init datalist update
initializeDatalist ( ) ;
} ) ( ) ;
} ) ;