vendor/assets/javascripts/webshims/shims/form-shim-extend.js in webshims-rails-1.11.3.1 vs vendor/assets/javascripts/webshims/shims/form-shim-extend.js in webshims-rails-1.11.6

- old
+ new

@@ -2,11 +2,10 @@ "use strict"; webshims.inputTypes = webshims.inputTypes || {}; //some helper-functions var cfg = webshims.cfg.forms; var bugs = webshims.bugs; -var isSubmit; var isNumber = function(string){ return (typeof string == 'number' || (string && string == string * 1)); }, typeModels = webshims.inputTypes, @@ -77,10 +76,11 @@ badInput: false, rangeUnderflow: false, rangeOverflow: false, stepMismatch: false, tooLong: false, + tooShort: false, patternMismatch: false, valueMissing: false, valid: true }; @@ -113,10 +113,13 @@ } ret = ret.filter('[type="radio"]'); } 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; if(!('type' in cache)){ @@ -129,15 +132,16 @@ } else { ret = !(val); } return ret; }, - tooLong: function(){ - return false; - }, patternMismatch: function(input, val, cache) { if(val === '' || cache.nodeName == 'select'){return false;} + if(!('type' in cache)){ + cache.type = getType(input[0]); + } + if(!patternTypes[cache.type]){return false;} var pattern = input.attr('pattern'); if(!pattern){return false;} try { pattern = new RegExp('^(?:' + pattern + ')$'); } catch(er){ @@ -148,10 +152,24 @@ return !(pattern.test(val)); } } ; +$.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 + if(cache.nodeName == 'select' || input.prop('defaultValue') == val){return false;} + if(!('type' in cache)){ + cache.type = getType(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; if(!('type' in cache)){ @@ -198,19 +216,16 @@ teardown: $.noop, handler: function(e, d){ if( e.type != 'submit' || e.testedValidity || !e.originalEvent || !$.nodeName(e.target, 'form') || $.prop(e.target, 'noValidate') ){return;} - isSubmit = true; e.testedValidity = true; - var notValid = !($(e.target).checkValidity()); + var notValid = !($(e.target).callProp('reportValidity')); if(notValid){ e.stopImmediatePropagation(); - isSubmit = false; return false; } - isSubmit = false; } }; $.event.special.submit = $.event.special.submit || {setup: function(){return false;}}; var submitSetup = $.event.special.submit.setup; @@ -273,10 +288,13 @@ //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 @@ -287,11 +305,11 @@ return $.extend({}, validityPrototype); } } }, 'prop'); -var baseCheckValidity = function(elem){ +var baseCheckValidity = function(elem, type){ var e, v = $.prop(elem, 'validity') ; if(v){ $.data(elem, 'cachedValidity', v); @@ -299,118 +317,134 @@ return true; } if( !v.valid ){ e = $.Event('invalid'); var jElm = $(elem).trigger(e); - if(isSubmit && !baseCheckValidity.unhandledInvalids && !e.isDefaultPrevented()){ + 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; -webshims.defineNodeNameProperty('form', 'checkValidity', { - 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]) ){ - ret = false; + +['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; } - return ret; } - } + }); }); -webshims.defineNodeNamesProperties(['input', 'textarea', 'select'], { - checkValidity: { - value: function(){ - baseCheckValidity.unhandledInvalids = false; - return baseCheckValidity($(this).getNativeElement()[0]); - } - }, - setCustomValidity: { - value: function(error){ - $.removeData(this, 'cachedValidity'); - webshims.data(this, 'customvalidationMessage', ''+error); - } - }, - willValidate: { - writeable: false, - get: (function(){ - var types = { - button: 1, - reset: 1, - hidden: 1, - image: 1 + + + +['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); } - ; - return function(){ - var elem = $(this).getNativeElement()[0]; - //elem.name && <- we don't use to make it easier for developers - return !!(!elem.disabled && !elem.readOnly && !types[elem.type] ); - }; - })() - }, - 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' ){ + }, + willValidate: { + writeable: false, + get: (function(){ + var types = { + button: 1, + reset: 1, + hidden: 1, + image: 1 + } + ; + return function(){ + var elem = $(this).getNativeElement()[0]; + return !!(!elem.readOnly && !types[elem.type] && !$(elem).is(':disabled') ); + }; + })() + }, + 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(), + 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; } - var val = jElm.val(), - cache = {nodeName: elem.nodeName.toLowerCase()} - ; - - validityState.customError = !!(webshims.data(elem, 'customvalidationMessage')); - if( validityState.customError ){ - validityState.valid = false; + } + }; + + ['checkValidity', 'reportValidity'].forEach(function(name){ + inputValidationAPI[name] = { + value: function(){ + baseCheckValidity.unhandledInvalids = false; + return baseCheckValidity($(this).getNativeElement()[0], name); } - - $.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; } - } -}, 'prop'); + }); + + webshims.defineNodeNameProperties(nodeName, inputValidationAPI, 'prop'); +}); + webshims.defineNodeNamesBooleanProperty(['input', 'textarea', 'select'], 'required', { set: function(value){ $(this).getShadowFocusElement().attr('aria-required', !!(value)+''); }, initAttr: Modernizr.localstorage //only if we have aria-support }); webshims.defineNodeNamesBooleanProperty(['input'], 'multiple'); -if(webshims.bugs.bustedValidity){ +if(bugs.bustedValidity){ webshims.defineNodeNameProperty('form', 'novalidate', { attr: { set: function(val){ webshims.data(this, 'bustedNoValidate', ''+val); @@ -449,10 +483,26 @@ return $.attr(this, 'novalidate') != null; } } }); +webshims.defineNodeNamesProperty(['input', 'textarea'], 'minLength', { + 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(Modernizr.inputtypes.date && /webkit/i.test(navigator.userAgent)){ (function(){ var noInputTriggerEvts = {updateInput: 1, input: 1}, fixInputTypes = { @@ -503,11 +553,11 @@ setTimeout(function(){ if(e && noFocusEvents[e.type]){ focusedin = false; } if(input){ - input.unbind('focusout blur', unbind).unbind('input change updateInput', trigger); + input.off('focusout blur', unbind).off('input change updateInput', trigger); trigger(); } input = null; }, 1); @@ -546,11 +596,11 @@ webshims.addReady(function(context, contextElem){ //start constrain-validation var focusElem; $('form', context) .add(contextElem.filter('form')) - .bind('invalid', $.noop) + .on('invalid', $.noop) ; try { if(context == document && !('form' in (document.activeElement || {}))) { focusElem = $('input[autofocus], select[autofocus], textarea[autofocus]', context).eq(0).getShadowFocusElement()[0]; @@ -722,19 +772,19 @@ formSubmitterDescriptors[attrName] = {}; } formSubmitterDescriptors[attrName].attr = { set: function(value){ formSubmitterDescriptors[attrName].attr._supset.call(this, value); - $(this).unbind(eventName).on(eventName, changeSubmitter); + $(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).unbind(eventName); + $(this).off(eventName); formSubmitterDescriptors[attrName].removeAttr._supvalue.call(this); } }; });