vendor/assets/javascripts/webshims/shims/combos/15.js in webshims-rails-1.10.3 vs vendor/assets/javascripts/webshims/shims/combos/15.js in webshims-rails-1.10.6

- old
+ new

@@ -1,18 +1,69 @@ //DOM-Extension helper -jQuery.webshims.register('dom-extend', function($, webshims, window, document, undefined){ +webshims.register('dom-extend', function($, webshims, window, document, undefined){ "use strict"; - webshims.assumeARIA = Modernizr.localstorage || Modernizr.video || Modernizr.boxsizing; + webshims.assumeARIA = $.support.getSetAttribute || Modernizr.canvas || Modernizr.video || Modernizr.boxsizing; if($('<input type="email" />').attr('type') == 'text' || $('<form />').attr('novalidate') === "" || ('required' in $('<input />')[0].attributes)){ webshims.error("IE browser modes are busted in IE10. Please test your HTML/CSS/JS with a real IE version or at least IETester or similiar tools"); } if(!$.parseHTML){ webshims.error("Webshims needs jQuery 1.8+ to work properly. Please update your jQuery version or downgrade webshims."); } + if (!webshims.cfg.no$Switch) { + var switch$ = function(){ + if (window.jQuery && (!window.$ || window.jQuery == window.$) && !window.jQuery.webshims) { + webshims.error("jQuery was included more than once. Make sure to include it only once! Webshims and other Plugins might not work properly."); + if (window.$) { + window.$ = webshims.$; + } + window.jQuery = webshims.$; + } + if(webshims.M != Modernizr){ + webshims.error("Modernizr was included more than once. Make sure to include it only once! Webshims and other scripts might not work properly."); + for(var i in Modernizr){ + if(!(i in webshims.M)){ + webshims.M[i] = Modernizr[i]; + } + } + Modernizr = webshims.M; + } + }; + switch$(); + setTimeout(switch$, 90); + $(switch$); + } +// (function(){ +// var hostNames = { +// 'afarkas.github.io': 1, +// localhost: 1, +// '127.0.0.1': 1 +// }; +// +// if( webshims.debug && (hostNames[location.hostname] || location.protocol == 'file:') ){ +// var list = $('<ul class="webshims-debug-list" />'); +// webshims.errorLog.push = function(message){ +// list.appendTo('body'); +// $('<li style="display: none;">'+ message +'</li>') +// .appendTo(list) +// .slideDown() +// .delay(3000) +// .slideUp(function(){ +// $(this).remove(); +// if(!$('li', list).length){ +// list.detach(); +// } +// }) +// ; +// }; +// $.each(webshims.errorLog, function(i, message){ +// webshims.errorLog.push(message); +// }); +// } +// })(); //shortcus var modules = webshims.modules; var listReg = /\s*,\s*/; @@ -26,10 +77,28 @@ var oldVal = $.fn.val; var singleVal = function(elem, name, val, pass, _argless){ return (_argless) ? oldVal.call($(elem)) : oldVal.call($(elem), val); }; + //jquery mobile and jquery ui + if(!$.widget){ + (function(){ + var _cleanData = $.cleanData; + $.cleanData = function( elems ) { + if(!$.widget){ + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + try { + $( elem ).triggerHandler( "remove" ); + // http://bugs.jquery.com/ticket/8235 + } catch( e ) {} + } + } + _cleanData( elems ); + }; + })(); + } + $.fn.val = function(val){ var elem = this[0]; if(arguments.length && val == null){ val = ''; @@ -59,10 +128,22 @@ }; $.fn.onTrigger = function(evt, fn){ return this.on(evt, fn).each(fn); }; + $.fn.onWSOff = function(evt, fn, trigger, evtDel){ + if(!evtDel){ + evtDel = document; + } + $(evtDel)[trigger ? 'onTrigger' : 'on'](evt, fn); + this.on('remove', function(e){ + if(!e.originalEvent){ + $(evtDel).off(evt, fn); + } + }); + }; + var dataID = '_webshimsLib'+ (Math.round(Math.random() * 1000)); var elementData = function(elem, key, val){ elem = elem.jquery ? elem[0] : elem; if(!elem){return val || {};} var data = $.data(elem, dataID); @@ -420,11 +501,11 @@ }; })(), implement: function(elem, type){ var data = elementData(elem, 'implemented') || elementData(elem, 'implemented', {}); if(data[type]){ - webshims.info(type +' already implemented for element #'+elem.id); + webshims.warn(type +' already implemented for element #'+elem.id); return false; } data[type] = true; return true; }, @@ -564,10 +645,16 @@ opts.shadowFocusElement = opts.shadowFocusElement[0]; } shadowFocusElementData = $.data(opts.shadowFocusElement, dataID) || $.data(opts.shadowFocusElement, dataID, shadowFocusElementData); } + $(nativeElem).on('remove', function(e){ + if (!e.originalEvent) { + $(shadowElem).remove(); + } + }); + nativeData.hasShadow = shadowElem; shadowFocusElementData.nativeElement = shadowData.nativeElement = nativeElem; shadowFocusElementData.shadowData = shadowData.shadowData = nativeData.shadowData = { nativeElement: nativeElem, shadowElement: shadowElem, @@ -1039,36 +1126,13 @@ } }); })(jQuery, document); -//additional tests for partial implementation of forms features -(function($){ +webshims.register('form-core', function($, webshims, window, document, undefined, options){ "use strict"; - var isWebkit = 'webkitURL' in window; - var Modernizr = window.Modernizr; - var webshims = $.webshims; - var bugs = webshims.bugs; - var form = $('<form action="#" style="width: 1px; height: 1px; overflow: hidden;"><select name="b" required="" /><input required="" name="a" /></form>'); - var testRequiredFind = function(){ - if(form[0].querySelector){ - try { - bugs.findRequired = !(form[0].querySelector('select:required')); - } catch(er){ - bugs.findRequired = false; - } - } - }; - var inputElem = $('input', form).eq(0); - var onDomextend = function(fn){ - webshims.loader.loadList(['dom-extend']); - webshims.ready('dom-extend', fn); - }; - - bugs.findRequired = false; - bugs.validationMessage = false; - + webshims.capturingEventPrevented = function(e){ if(!e._isPolyfilled){ var isDefaultPrevented = e.isDefaultPrevented; var preventDefault = e.preventDefault; e.preventDefault = function(){ @@ -1083,200 +1147,263 @@ }; e._isPolyfilled = true; } }; - if(!Modernizr.formvalidation || bugs.bustedValidity){ - testRequiredFind(); - } else { + if(Modernizr.formvalidation && !webshims.bugs.bustedValidity){ //create delegatable events webshims.capturingEvents(['invalid'], true); - - if(window.opera || window.testGoodWithFix){ + } + + var isValid = function(elem){ + return ($.prop(elem, 'validity') || {valid: 1}).valid; + }; + var lazyLoad = function(){ + var toLoad = ['form-validation']; + if(options.lazyCustomMessages){ + options.customMessages = true; + toLoad.push('form-message'); + } + if(options.addValidators){ + toLoad.push('form-validators'); + } + webshims.reTest(toLoad); + $(document).off('.lazyloadvalidation'); + }; + /* + * Selectors for all browsers + */ + var hasInvalid = function(elem){ + var ret = false; + $(elem).jProp('elements').each(function(){ + ret = $(this).is(':invalid'); + if(ret){ + return false; + } + }); + return ret; + }; + var rElementsGroup = /^(?:form)$/i;///^(?:form|fieldset)$/i + $.extend($.expr[":"], { + "valid-element": function(elem){ + return rElementsGroup.test(elem.nodeName || '') ? !hasInvalid(elem) :!!($.prop(elem, 'willValidate') && isValid(elem)); + }, + "invalid-element": function(elem){ + return rElementsGroup.test(elem.nodeName || '') ? hasInvalid(elem) : !!($.prop(elem, 'willValidate') && !isValid(elem)); + }, + "required-element": function(elem){ + return !!($.prop(elem, 'willValidate') && $.prop(elem, 'required')); + }, + "user-error": function(elem){ + return ($.prop(elem, 'willValidate') && $(elem).hasClass('user-error')); + }, + "optional-element": function(elem){ + return !!($.prop(elem, 'willValidate') && $.prop(elem, 'required') === false); + } + }); + + ['valid', 'invalid', 'required', 'optional'].forEach(function(name){ + $.expr[":"][name] = $.expr.filters[name+"-element"]; + }); + + + $.expr[":"].focus = function( elem ) { + try { + var doc = elem.ownerDocument; + return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()); + } catch(e){} + return false; + }; + + webshims.triggerInlineForm = function(elem, event){ + $(elem).trigger(event); + }; + + var lazyLoadProxy = function(obj, fn, args){ + lazyLoad(); + webshims.ready('form-validation', function(){ + obj[fn].apply(obj, args); + }); + }; + + + webshims.wsPopover = { + id: 0, + _create: function(){ + this.options = $.extend({}, webshims.cfg.wspopover, this.options); + this.id = webshims.wsPopover.id++; + this.eventns = '.wsoverlay' + this.id; + this.timers = {}; + this.element = $('<div class="ws-popover" tabindex="-1"><div class="ws-po-outerbox"><div class="ws-po-arrow"><div class="ws-po-arrowbox" /></div><div class="ws-po-box" /></div></div>'); + this.contentElement = $('.ws-po-box', this.element); + this.lastElement = $([]); + this.bindElement(); - form.appendTo('head'); + this.element.data('wspopover', this); - testRequiredFind(); - bugs.validationMessage = !(inputElem.prop('validationMessage')); - - webshims.reTest(['form-native-extend', 'form-message']); - - form.remove(); - - $(function(){ - onDomextend(function(){ - - //Opera shows native validation bubbles in case of input.checkValidity() - // Opera 11.6/12 hasn't fixed this issue right, it's buggy - var preventDefault = function(e){ - e.preventDefault(); - }; - - ['form', 'input', 'textarea', 'select'].forEach(function(name){ - var desc = webshims.defineNodeNameProperty(name, 'checkValidity', { - prop: { - value: function(){ - if (!webshims.fromSubmit) { - $(this).on('invalid.checkvalidity', preventDefault); - } - - webshims.fromCheckValidity = true; - var ret = desc.prop._supvalue.apply(this, arguments); - if (!webshims.fromSubmit) { - $(this).unbind('invalid.checkvalidity', preventDefault); - } - webshims.fromCheckValidity = false; - return ret; - } - } - }); - }); - - }); + }, + options: {}, + content: function(html){ + this.contentElement.html(html); + }, + bindElement: function(){ + var that = this; + var stopBlur = function(){ + that.stopBlur = false; + }; + this.preventBlur = function(e){ + that.stopBlur = true; + clearTimeout(that.timers.stopBlur); + that.timers.stopBlur = setTimeout(stopBlur, 9); + }; + this.element.on({ + 'mousedown': this.preventBlur }); + }, + show: function(){ + lazyLoadProxy(this, 'show', arguments); } - - if(isWebkit && !webshims.bugs.bustedValidity){ - (function(){ - var elems = /^(?:textarea|input)$/i; - var form = false; - - document.addEventListener('contextmenu', function(e){ - if(elems.test( e.target.nodeName || '') && (form = e.target.form)){ - setTimeout(function(){ - form = false; - }, 1); - } - }, false); - - $(window).on('invalid', function(e){ - if(e.originalEvent && form && form == e.target.form){ - e.wrongWebkitInvalid = true; - e.stopImmediatePropagation(); - } - }); - - })(); + }; + + /* some extra validation UI */ + webshims.validityAlert = { + showFor: function(){ + lazyLoadProxy(this, 'showFor', arguments); } - } - - $.webshims.register('form-core', function($, webshims, window, document, undefined, options){ + }; - var checkTypes = {checkbox: 1, radio: 1}; - var emptyJ = $([]); - var bugs = webshims.bugs; - var getGroupElements = function(elem){ - elem = $(elem); - var name; - var form; - var ret = emptyJ; - if(elem[0].type == 'radio'){ - form = elem.prop('form'); - name = elem[0].name; - if(!name){ - ret = elem; - } else if(form){ - ret = $(form[name]); - } else { - ret = $(document.getElementsByName(name)).filter(function(){ - return !$.prop(this, 'form'); - }); - } - ret = ret.filter('[type="radio"]'); - } - return ret; - }; + + /* extension, but also used to fix native implementation workaround/bugfixes */ + (function(){ + var firstEvent, + invalids = [], + stopSubmitTimer, + form + ; - var getContentValidationMessage = webshims.getContentValidationMessage = function(elem, validity, key){ - var message = $(elem).data('errormessage') || elem.getAttribute('x-moz-errormessage') || ''; - if(key && message[key]){ - message = message[key]; + $(document).on('invalid', function(e){ + if(e.wrongWebkitInvalid){return;} + var jElm = $(e.target); + + + if(!firstEvent){ + //trigger firstinvalid + firstEvent = $.Event('firstinvalid'); + firstEvent.isInvalidUIPrevented = e.isDefaultPrevented; + var firstSystemInvalid = $.Event('firstinvalidsystem'); + $(document).triggerHandler(firstSystemInvalid, {element: e.target, form: e.target.form, isInvalidUIPrevented: e.isDefaultPrevented}); + jElm.trigger(firstEvent); } - if(typeof message == 'object'){ - validity = validity || $.prop(elem, 'validity') || {valid: 1}; - if(!validity.valid){ - $.each(validity, function(name, prop){ - if(prop && name != 'valid' && message[name]){ - message = message[name]; - return false; - } - }); - } + + //if firstinvalid was prevented all invalids will be also prevented + if( firstEvent && firstEvent.isDefaultPrevented() ){ + e.preventDefault(); } - - if(typeof message == 'object'){ - message = message.defaultMessage; + invalids.push(e.target); + e.extraData = 'fix'; + clearTimeout(stopSubmitTimer); + stopSubmitTimer = setTimeout(function(){ + var lastEvent = {type: 'lastinvalid', cancelable: false, invalidlist: $(invalids)}; + //reset firstinvalid + firstEvent = false; + invalids = []; + $(e.target).trigger(lastEvent, lastEvent); + }, 9); + jElm = null; + }); + })(); + + + webshims.getContentValidationMessage = function(elem, validity, key){ + var message = $(elem).data('errormessage') || elem.getAttribute('x-moz-errormessage') || ''; + if(key && message[key]){ + message = message[key]; + } + if(typeof message == 'object'){ + validity = validity || $.prop(elem, 'validity') || {valid: 1}; + if(!validity.valid){ + $.each(validity, function(name, prop){ + if(prop && name != 'valid' && message[name]){ + message = message[name]; + return false; + } + }); } - return message || ''; - }; + } - /* - * Selectors for all browsers - */ - var rangeTypes = {number: 1, range: 1, date: 1/*, time: 1, 'datetime-local': 1, datetime: 1, month: 1, week: 1*/}; - var hasInvalid = function(elem){ - var ret = false; - $($.prop(elem, 'elements')).each(function(){ - ret = $(this).is(':invalid'); - if(ret){ - return false; + if(typeof message == 'object'){ + message = message.defaultMessage; + } + return message || ''; + }; + + $.fn.getErrorMessage = function(key){ + var message = ''; + var elem = this[0]; + if(elem){ + message = webshims.getContentValidationMessage(elem, false, key) || $.prop(elem, 'customValidationMessage') || $.prop(elem, 'validationMessage'); + } + return message; + }; + + + webshims.ready('forms', function(){ + $(document).on('focusin.lazyloadvalidation', function(e){ + if('form' in e.target && $(e.target).is(':invalid')){ + lazyLoad(); + } + }); + }); + webshims.ready('WINDOWLOAD', lazyLoad); + if(options.overrideMessages){ + options.customMessages = true; + webshims.reTest('form-message'); + webshims.error('overrideMessages is deprecated. use customMessages instead.'); + } + if(options.replaceValidationUI){ + webshims.ready('DOM forms', function(){ + $(document).on('firstinvalid', function(e){ + if(!e.isInvalidUIPrevented()){ + e.preventDefault(); + webshims.validityAlert.showFor( e.target ); } }); - return ret; - }; - $.extend($.expr[":"], { - "valid-element": function(elem){ - return $.nodeName(elem, 'form') ? !hasInvalid(elem) :!!($.prop(elem, 'willValidate') && isValid(elem)); - }, - "invalid-element": function(elem){ - return $.nodeName(elem, 'form') ? hasInvalid(elem) : !!($.prop(elem, 'willValidate') && !isValid(elem)); - }, - "required-element": function(elem){ - return !!($.prop(elem, 'willValidate') && $.prop(elem, 'required')); - }, - "user-error": function(elem){ - return ($.prop(elem, 'willValidate') && $(elem).hasClass('user-error')); - }, - "optional-element": function(elem){ - return !!($.prop(elem, 'willValidate') && $.prop(elem, 'required') === false); - }, - "in-range": function(elem){ - if(!rangeTypes[$.prop(elem, 'type')] || !$.prop(elem, 'willValidate')){ - return false; - } - var val = $.prop(elem, 'validity'); - return !!(val && !val.rangeOverflow && !val.rangeUnderflow); - }, - "out-of-range": function(elem){ - if(!rangeTypes[$.prop(elem, 'type')] || !$.prop(elem, 'willValidate')){ - return false; - } - var val = $.prop(elem, 'validity'); - return !!(val && (val.rangeOverflow || val.rangeUnderflow)); - } - }); + } +}); + + +if(!Modernizr.formvalidation || webshims.bugs.bustedValidity){ +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 isSubmit; + +var isNumber = function(string){ + return (typeof string == 'number' || (string && string == string * 1)); + }, + typeModels = webshims.inputTypes, + checkTypes = { + radio: 1, + checkbox: 1 + }, + getType = function(elem){ + return (elem.getAttribute('type') || elem.type || '').toLowerCase(); + } +; + +(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; + } - ['valid', 'invalid', 'required', 'optional'].forEach(function(name){ - $.expr[":"][name] = $.expr.filters[name+"-element"]; - }); - - - $.expr[":"].focus = function( elem ) { - try { - var doc = elem.ownerDocument; - return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()); - } catch(e){} - return false; - }; - - - var customEvents = $.event.customEvent || {}; - var isValid = function(elem){ - return ($.prop(elem, 'validity') || {valid: 1}).valid; - }; - if (bugs.bustedValidity || bugs.findRequired) { (function(){ var find = $.find; var matchesSelector = $.find.matchesSelector; @@ -1307,484 +1434,12 @@ }; } })(); } - - //ToDo needs testing - var oldAttr = $.prop; - var changeVals = {selectedIndex: 1, value: 1, checked: 1, disabled: 1, readonly: 1}; - $.prop = function(elem, name, val){ - var ret = oldAttr.apply(this, arguments); - if(elem && 'form' in elem && changeVals[name] && val !== undefined && $(elem).hasClass(invalidClass)){ - if(isValid(elem)){ - $(elem).getShadowElement().removeClass(invalidClass); - if(name == 'checked' && val) { - getGroupElements(elem).not(elem).removeClass(invalidClass).removeAttr('aria-invalid'); - } - } - } - return ret; - }; - - var returnValidityCause = function(validity, elem){ - var ret; - $.each(validity, function(name, value){ - if(value){ - ret = (name == 'customError') ? $.prop(elem, 'validationMessage') : name; - return false; - } - }); - return ret; - }; - - var isInGroup = function(name){ - var ret; - try { - ret = document.activeElement.name === name; - } catch(e){} - return ret; - }; - /* form-ui-invalid/form-ui-valid are deprecated. use user-error/user-success instead */ - var invalidClass = 'user-error'; - var validClass = 'user-success'; - var stopChangeTypes = { - time: 1, - date: 1, - month: 1, - datetime: 1, - week: 1, - 'datetime-local': 1 - }; - var switchValidityClass = function(e){ - var elem, timer; - if(!e.target){return;} - elem = $(e.target).getNativeElement()[0]; - if(elem.type == 'submit' || !$.prop(elem, 'willValidate')){return;} - timer = $.data(elem, 'webshimsswitchvalidityclass'); - var switchClass = function(){ - if(e.type == 'focusout' && elem.type == 'radio' && isInGroup(elem.name)){return;} - var validity = $.prop(elem, 'validity'); - var shadowElem = $(elem).getShadowElement(); - var addClass, removeClass, trigger, generaltrigger, validityCause; - - if(isWebkit && e.type == 'change' && !bugs.bustedValidity && stopChangeTypes[shadowElem.prop('type')] && shadowElem.is(':focus')){return;} - - $(elem).trigger('refreshCustomValidityRules'); - - if(validity.valid){ - if(!shadowElem.hasClass(validClass)){ - addClass = validClass; - removeClass = invalidClass; - generaltrigger = 'changedvaliditystate'; - trigger = 'changedvalid'; - if(checkTypes[elem.type] && elem.checked){ - getGroupElements(elem).not(elem).removeClass(removeClass).addClass(addClass).removeAttr('aria-invalid'); - } - $.removeData(elem, 'webshimsinvalidcause'); - } - } else { - validityCause = returnValidityCause(validity, elem); - if($.data(elem, 'webshimsinvalidcause') != validityCause){ - $.data(elem, 'webshimsinvalidcause', validityCause); - generaltrigger = 'changedvaliditystate'; - } - if(!shadowElem.hasClass(invalidClass)){ - addClass = invalidClass; - removeClass = validClass; - if (checkTypes[elem.type] && !elem.checked) { - getGroupElements(elem).not(elem).removeClass(removeClass).addClass(addClass); - } - trigger = 'changedinvalid'; - } - } - - if(addClass){ - shadowElem.addClass(addClass).removeClass(removeClass); - //jQuery 1.6.1 IE9 bug (doubble trigger bug) - setTimeout(function(){ - $(elem).trigger(trigger); - }, 0); - } - if(generaltrigger){ - setTimeout(function(){ - $(elem).trigger(generaltrigger); - }, 0); - } - - $.removeData(elem, 'webshimsswitchvalidityclass'); - }; - - if(timer){ - clearTimeout(timer); - } - if(e.type == 'refreshvalidityui'){ - switchClass(); - } else { - $.data(elem, 'webshimsswitchvalidityclass', setTimeout(switchClass, 9)); - } - }; - - $(document).on(options.validityUIEvents || 'focusout change refreshvalidityui', switchValidityClass); - customEvents.changedvaliditystate = true; - customEvents.refreshCustomValidityRules = true; - customEvents.changedvalid = true; - customEvents.changedinvalid = true; - customEvents.refreshvalidityui = true; - - - webshims.triggerInlineForm = function(elem, event){ - $(elem).trigger(event); - }; - - webshims.modules["form-core"].getGroupElements = getGroupElements; - - - var setRoot = function(){ - webshims.scrollRoot = (isWebkit || document.compatMode == 'BackCompat') ? - $(document.body) : - $(document.documentElement) - ; - }; - var minWidth = (Modernizr.boxSizing || Modernizr['display-table'] || $.support.getSetAttribute) ? - 'minWidth' : - 'width' - ; - setRoot(); - webshims.ready('DOM', setRoot); - - webshims.getRelOffset = function(posElem, relElem){ - posElem = $(posElem); - var offset = $(relElem).offset(); - var bodyOffset; - $.swap($(posElem)[0], {visibility: 'hidden', display: 'inline-block', left: 0, top: 0}, function(){ - bodyOffset = posElem.offset(); - }); - offset.top -= bodyOffset.top; - offset.left -= bodyOffset.left; - return offset; - }; - - webshims.wsPopover = { - _create: function(){ - this.options = $.extend({}, webshims.cfg.wspopover, this.options); - this.id = webshims.wsPopover.id++; - this.eventns = '.wsoverlay'+this.id; - this.timers = {}; - this.element = $('<div class="ws-popover" tabindex="-1"><div class="ws-po-outerbox"><div class="ws-po-arrow"><div class="ws-po-arrowbox" /></div><div class="ws-po-box" /></div></div>'); - this.contentElement = $('.ws-po-box', this.element); - this.lastElement = $([]); - this.bindElement(); - - this.element.data('wspopover', this); - - }, - options: {}, - content: function(html){ - this.contentElement.html(html); - }, - bindElement: function(){ - var that = this; - var stopBlur = function(){ - that.stopBlur = false; - }; - this.preventBlur = function(e){ - that.stopBlur = true; - clearTimeout(that.timers.stopBlur); - that.timers.stopBlur = setTimeout(stopBlur, 9); - }; - this.element.on({ - 'mousedown': this.preventBlur - }); - }, - - isInElement: function(container, contained){ - return container == contained || $.contains(container, contained); - }, - show: function(element){ - var e = $.Event('wspopoverbeforeshow'); - this.element.trigger(e); - if(e.isDefaultPrevented() || this.isVisible){return;} - this.isVisible = true; - element = $(element || this.options.prepareFor).getNativeElement() ; - - var that = this; - var visual = $(element).getShadowElement(); - - this.clear(); - this.element.removeClass('ws-po-visible').css('display', 'none'); - - this.prepareFor(element, visual); - - this.position(visual); - that.timers.show = setTimeout(function(){ - that.element.css('display', ''); - that.timers.show = setTimeout(function(){ - that.element.addClass('ws-po-visible').trigger('wspopovershow'); - }, 9); - }, 9); - $(document).on('focusin'+this.eventns+' mousedown'+this.eventns, function(e){ - if(that.options.hideOnBlur && !that.stopBlur && !that.isInElement(that.lastElement[0] || document.body, e.target) && !that.isInElement(element[0] || document.body, e.target) && !that.isInElement(that.element[0], e.target)){ - that.hide(); - } - }); - $(window).on('resize'+this.eventns + ' pospopover'+this.eventns, function(){ - clearTimeout(that.timers.repos); - that.timers.repos = setTimeout(function(){ - that.position(visual); - }, 900); - }); - }, - prepareFor: function(element, visual){ - var onBlur; - var opts = $.extend({}, this.options, $(element.prop('form') || []).data('wspopover') || {}, element.data('wspopover')); - var that = this; - var css = {}; - this.lastElement = $(element).getShadowFocusElement(); - if(opts.appendTo == 'element'){ - this.element.insertAfter(element); - } else { - this.element.appendTo(opts.appendTo); - } - - this.element.attr({ - 'data-class': element.prop('className'), - 'data-id': element.prop('id') - }); - - css[minWidth] = opts.constrainWidth ? visual.outerWidth() : ''; - - this.element.css(css); - - if(opts.hideOnBlur){ - onBlur = function(e){ - if(that.stopBlur){ - e.stopImmediatePropagation(); - } else { - that.hide(); - } - }; - - that.timers.bindBlur = setTimeout(function(){ - that.lastElement.off(that.eventns).on('focusout'+that.eventns + ' blur'+that.eventns, onBlur); - that.lastElement.getNativeElement().off(that.eventns); - }, 10); - - - } - - if(!this.prepared){ - - if($.fn.bgIframe){ - this.element.bgIframe(); - } - } - this.prepared = true; - }, - clear: function(){ - $(window).off(this.eventns); - $(document).off(this.eventns); - - this.stopBlur = false; - $.each(this.timers, function(timerName, val){ - clearTimeout(val); - }); - }, - hide: function(){ - var e = $.Event('wspopoverbeforehide'); - this.element.trigger(e); - if(e.isDefaultPrevented() || !this.isVisible){return;} - this.isVisible = false; - var that = this; - var forceHide = function(){ - that.element.css('display', 'none').attr({'data-id': '', 'data-class': '', 'hidden': 'hidden'}); - clearTimeout(that.timers.forcehide); - }; - this.clear(); - this.element.removeClass('ws-po-visible').trigger('wspopoverhide'); - $(window).on('resize'+this.eventns, forceHide); - that.timers.forcehide = setTimeout(forceHide, 999); - }, - position: function(element){ - var offset = webshims.getRelOffset(this.element.css({marginTop: 0, marginLeft: 0, marginRight: 0, marginBottom: 0}).removeAttr('hidden'), element); - offset.top += element.outerHeight(); - this.element.css({marginTop: '', marginLeft: '', marginRight: '', marginBottom: ''}).css(offset); - } - }; - - webshims.wsPopover.id = 0; - - /* some extra validation UI */ - webshims.validityAlert = (function(){ - - - var focusTimer = false; - - var api = webshims.objectCreate(webshims.wsPopover, {}, options.messagePopover); - var boundHide = api.hide.bind(api); - - api.element.addClass('validity-alert').attr({role: 'alert'}); - $.extend(api, { - hideDelay: 5000, - showFor: function(elem, message, noFocusElem, noBubble){ - - elem = $(elem).getNativeElement(); - this.clear(); - this.hide(); - if(!noBubble){ - this.getMessage(elem, message); - - this.show(elem); - if(this.hideDelay){ - this.timers.delayedHide = setTimeout(boundHide, this.hideDelay); - } - - } - - if(!noFocusElem){ - this.setFocus(elem); - } - }, - setFocus: function(element){ - var focusElem = $(element).getShadowFocusElement(); - var scrollTop = webshims.scrollRoot.scrollTop(); - var elemTop = focusElem.offset().top - 30; - var smooth; - - if(scrollTop > elemTop){ - webshims.scrollRoot.animate( - {scrollTop: elemTop - 5}, - { - queue: false, - duration: Math.max( Math.min( 600, (scrollTop - elemTop) * 1.5 ), 80 ) - } - ); - smooth = true; - } - try { - focusElem[0].focus(); - } catch(e){} - if(smooth){ - webshims.scrollRoot.scrollTop(scrollTop); - setTimeout(function(){ - webshims.scrollRoot.scrollTop(scrollTop); - }, 0); - } - - $(window).triggerHandler('pospopover'+this.eventns); - }, - getMessage: function(elem, message){ - if (!message) { - message = getContentValidationMessage(elem[0]) || elem.prop('customValidationMessage') || elem.prop('validationMessage'); - } - if (message) { - api.contentElement.text(message); - } else { - this.hide(); - } - } - }); - - - return api; - })(); - - - /* extension, but also used to fix native implementation workaround/bugfixes */ - (function(){ - var firstEvent, - invalids = [], - stopSubmitTimer, - form - ; - - $(document).on('invalid', function(e){ - if(e.wrongWebkitInvalid){return;} - var jElm = $(e.target); - var shadowElem = jElm.getShadowElement(); - if(!shadowElem.hasClass(invalidClass)){ - shadowElem.addClass(invalidClass).removeClass(validClass); - setTimeout(function(){ - $(e.target).trigger('changedinvalid').trigger('changedvaliditystate'); - }, 0); - } - - if(!firstEvent){ - //trigger firstinvalid - firstEvent = $.Event('firstinvalid'); - firstEvent.isInvalidUIPrevented = e.isDefaultPrevented; - var firstSystemInvalid = $.Event('firstinvalidsystem'); - $(document).triggerHandler(firstSystemInvalid, {element: e.target, form: e.target.form, isInvalidUIPrevented: e.isDefaultPrevented}); - jElm.trigger(firstEvent); - } - - //if firstinvalid was prevented all invalids will be also prevented - if( firstEvent && firstEvent.isDefaultPrevented() ){ - e.preventDefault(); - } - invalids.push(e.target); - e.extraData = 'fix'; - clearTimeout(stopSubmitTimer); - stopSubmitTimer = setTimeout(function(){ - var lastEvent = {type: 'lastinvalid', cancelable: false, invalidlist: $(invalids)}; - //reset firstinvalid - firstEvent = false; - invalids = []; - $(e.target).trigger(lastEvent, lastEvent); - }, 9); - jElm = null; - shadowElem = null; - }); - })(); - - $.fn.getErrorMessage = function(){ - var message = ''; - var elem = this[0]; - if(elem){ - message = getContentValidationMessage(elem) || $.prop(elem, 'customValidationMessage') || $.prop(elem, 'validationMessage'); - } - return message; - }; - - if(options.replaceValidationUI){ - if(options.overrideMessages && (options.customMessages || options.customMessages == null)){ - options.customMessages = true; - options.overrideMessages = false; - webshims.info("set overrideMessages to false. Use customMessages instead"); - } - webshims.ready('DOM forms', function(){ - $(document).on('firstinvalid', function(e){ - if(!e.isInvalidUIPrevented()){ - e.preventDefault(); - $.webshims.validityAlert.showFor( e.target ); - } - }); - }); - } - }); - -})(jQuery); -if(!Modernizr.formvalidation || jQuery.webshims.bugs.bustedValidity){ -jQuery.webshims.register('form-shim-extend', function($, webshims, window, document){ -"use strict"; -webshims.inputTypes = webshims.inputTypes || {}; -//some helper-functions -var cfg = webshims.cfg.forms; -var isSubmit; - -var isNumber = function(string){ - return (typeof string == 'number' || (string && string == string * 1)); - }, - typeModels = webshims.inputTypes, - checkTypes = { - radio: 1, - checkbox: 1 - }, - getType = function(elem){ - return (elem.getAttribute('type') || elem.type || '').toLowerCase(); } -; +})(); //API to add new input types webshims.addInputType = function(type, obj){ typeModels[type] = obj; }; @@ -1809,22 +1464,44 @@ var option = $('> option:first-child', select); return !!option.prop('selected'); } return false; }; - +var modules = webshims.modules; +var emptyJ = $([]); +var getGroupElements = function(elem){ + elem = $(elem); + var name; + var form; + var ret = emptyJ; + if(elem[0].type == 'radio'){ + form = elem.prop('form'); + name = elem[0].name; + if(!name){ + ret = elem; + } else if(form){ + ret = $(form[name]); + } else { + ret = $(document.getElementsByName(name)).filter(function(){ + return !$.prop(this, 'form'); + }); + } + ret = ret.filter('[type="radio"]'); + } + return ret; +}; var validityRules = { valueMissing: function(input, val, cache){ if(!input.prop('required')){return false;} var ret = false; if(!('type' in cache)){ cache.type = getType(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') : !webshims.modules["form-core"].getGroupElements(input).filter(':checked')[0]; + ret = (cache.type == 'checkbox') ? !input.is(':checked') : !getGroupElements(input).filter(':checked')[0]; } else { ret = !(val); } return ret; }, @@ -2615,10 +2292,56 @@ } catch (er) {} }); +if(!Modernizr.input.list){ + webshims.defineNodeNameProperty('datalist', 'options', { + prop: { + writeable: false, + get: function(){ + var elem = this; + var select = $('select', elem); + var options; + if(select[0]){ + options = select[0].options; + } else { + options = $('option', elem).get(); + 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; + } + } + }); + + webshims.ready('form-datalist', function(){ + 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' + } + }); + }); + +} + if(!Modernizr.formattribute || !Modernizr.fieldsetdisabled){ (function(){ (function(prop, undefined){ $.prop = function(elem, name, value){ var ret; @@ -2866,11 +2589,13 @@ }, removeAttr: { value: function(){ this.removeAttribute(name); if(removeProp){ - delete this.value; + try { + delete this.value; + } catch(er){} } updateProgress.isInChange = name; updateProgress(this); updateProgress.isInChange = false; } @@ -2965,21 +2690,21 @@ $(this).closest('select').each(selectChange); }); webshims.onNodeNamesPropertyModify('input', 'checked', function(value, boolVal){ var type = this.type; if(type == 'radio' && boolVal){ - webshims.modules["form-core"].getGroupElements(this).each(checkChange); + getGroupElements(this).each(checkChange); } else if(checkInputs[type]) { $(this).each(checkChange); } }); $(document).on('change', function(e){ if(checkInputs[e.target.type]){ if(e.target.type == 'radio'){ - webshims.modules["form-core"].getGroupElements(e.target).each(checkChange); + getGroupElements(e.target).each(checkChange); } else { $(e.target)[$.prop(e.target, 'checked') ? 'addClass' : 'removeClass']('prop-checked'); } } else if(e.target.nodeName.toLowerCase() == 'select'){ $(e.target).each(selectChange); @@ -2993,11 +2718,11 @@ var prop; if(checkInputs[this.type]){ prop = 'checked'; } else if(this.nodeName.toLowerCase() == 'option'){ prop = 'selected'; - } + } if(prop){ $(this)[$.prop(this, prop) ? 'addClass' : 'removeClass']('prop-checked'); } }) @@ -3005,17 +2730,45 @@ }); })(); } (function(){ + var bustedPlaceholder; Modernizr.textareaPlaceholder = !!('placeholder' in $('<textarea />')[0]); - if(Modernizr.input.placeholder && Modernizr.textareaPlaceholder){return;} + if(Modernizr.input.placeholder && options.overridePlaceholder){ + bustedPlaceholder = true; + } + if(Modernizr.input.placeholder && Modernizr.textareaPlaceholder && !bustedPlaceholder){ + (function(){ + var ua = navigator.userAgent; + + if(ua.indexOf('Mobile') != -1 && ua.indexOf('Safari') != -1){ + $(window).on('orientationchange', (function(){ + var timer; + var retVal = function(i, value){ + return value; + }; + + var set = function(){ + $('input[placeholder], textarea[placeholder]').attr('placeholder', retVal); + }; + return function(e){ + clearTimeout(timer); + timer = setTimeout(set, 9); + }; + })()); + } + })(); + + //abort + return; + } var isOver = (webshims.cfg.forms.placeholderType == 'over'); var isResponsive = (webshims.cfg.forms.responsivePlaceholder); var polyfillElements = ['textarea']; - if(!Modernizr.input.placeholder){ + if(!Modernizr.input.placeholder || bustedPlaceholder){ polyfillElements.push('input'); } var setSelection = function(elem){ try { @@ -3148,11 +2901,11 @@ tel: 1, number: 1 } ; - if(webshims.modules["form-number-date-ui"].loaded){ + if(modules["form-number-date-ui"].loaded){ delete allowedPlaceholder.number; } return { create: function(elem){ @@ -3166,15 +2919,15 @@ changePlaceholderVisibility(this, false, false, data, e.type ); data.box[e.type == 'focus' ? 'addClass' : 'removeClass']('placeholder-focused'); }); if((form = $.prop(elem, 'form'))){ - $(form).on('reset.placeholder', function(e){ + $(elem).onWSOff('reset.placeholder', function(e){ setTimeout(function(){ changePlaceholderVisibility(elem, false, false, data, e.type ); }, 0); - }); + }, false, form); } if(elem.type == 'password' || isOver){ data.text = createPlaceholder(elem); if(isResponsive || $(elem).is('.responsive-width') || (elem.currentStyle || {width: ''}).width.indexOf('%') != -1){ @@ -3209,43 +2962,41 @@ $.each(['Left', 'Top'], function(i, side){ var size = (parseInt($.css(elem, 'padding'+ side), 10) || 0) + Math.max((parseInt($.css(elem, 'margin'+ side), 10) || 0), 0) + (parseInt($.css(elem, 'border'+ side +'Width'), 10) || 0); data.text.css('padding'+ side, size); }); - $(document) - .onTrigger('updateshadowdom', function(){ + $(elem) + .onWSOff('updateshadowdom', function(){ var height, width; if((width = elem.offsetWidth) || (height = elem.offsetHeight)){ data.text .css({ width: width, height: height }) .css($(elem).position()) ; } - }) + }, true) ; } else { var reset = function(e){ if($(elem).hasClass('placeholder-visible')){ hidePlaceholder(elem, data, ''); - if(e && e.type == 'submit'){ - setTimeout(function(){ - if(e.isDefaultPrevented()){ - changePlaceholderVisibility(elem, false, false, data ); - } - }, 9); - } + setTimeout(function(){ + if(!e || e.type != 'submit' || e.isDefaultPrevented()){ + changePlaceholderVisibility(elem, false, false, data ); + } + }, 9); } }; - $(window).on('beforeunload', reset); + $(elem).onWSOff('beforeunload', reset, false, window); data.box = $(elem); if(form){ - $(form).submit(reset); + $(elem).onWSOff('submit', reset, false, form); } } return data; }, @@ -3274,15 +3025,24 @@ polyfillElements.forEach(function(nodeName){ var desc = webshims.defineNodeNameProperty(nodeName, 'placeholder', { attr: { set: function(val){ var elem = this; - webshims.contentAttr(elem, 'placeholder', val); + if(bustedPlaceholder){ + webshims.data(elem, 'bustedPlaceholder', val); + elem.placeholder = ''; + } else { + webshims.contentAttr(elem, 'placeholder', val); + } pHolder.update(elem, val); }, get: function(){ - return webshims.contentAttr(this, 'placeholder'); + var placeholder; + if(bustedPlaceholder){ + placeholder = webshims.data(this, 'bustedPlaceholder'); + } + return placeholder || webshims.contentAttr(this, 'placeholder'); } }, reflect: true, initAttr: true }); @@ -3295,11 +3055,13 @@ ['attr', 'prop'].forEach(function(propType){ placeholderValueDesc[propType] = { set: function(val){ var elem = this; var placeholder; - + if(bustedPlaceholder){ + placeholder = webshims.data(elem, 'bustedPlaceholder'); + } if(!placeholder){ placeholder = webshims.contentAttr(elem, 'placeholder'); } $.removeData(elem, 'cachedValidity'); var ret = desc[propType]._supset.call(elem, val); @@ -3465,15 +3227,19 @@ })(); }); //webshims.ready end }//end formvalidation -jQuery.webshims.register('form-message', function($, webshims, window, document, undefined, options){ +webshims.register('form-message', function($, webshims, window, document, undefined, options){ "use strict"; + if(options.overrideMessages){ + options.customMessages = true; + webshims.error('overrideMessages is deprecated. use customMessages instead.'); + } var validityMessages = webshims.validityMessages; - var implementProperties = (options.overrideMessages || options.customMessages) ? ['customValidationMessage'] : []; + var implementProperties = options.customMessages ? ['customValidationMessage'] : []; validityMessages.en = $.extend(true, { typeMismatch: { defaultMessage: 'Please enter a valid value.', email: 'Please enter an email address.', @@ -3500,21 +3266,21 @@ } }, (validityMessages.en || validityMessages['en-US'] || {})); if(typeof validityMessages['en'].valueMissing == 'object'){ ['select', 'radio'].forEach(function(type){ - validityMessages.en.valueMissing[type] = 'Please select an option.'; + 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] = 'Value must be at or after {%min}.'; + 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] = 'Value must be at or before {%max}.'; + validityMessages.en.rangeOverflow[type] = validityMessages.en.rangeOverflow[type] || 'Value must be at or before {%max}.'; }); } validityMessages['en-US'] = validityMessages['en-US'] || validityMessages.en; validityMessages[''] = validityMessages[''] || validityMessages['en-US']; @@ -3546,21 +3312,21 @@ } }, (validityMessages.de || {})); if(typeof validityMessages.de.valueMissing == 'object'){ ['select', 'radio'].forEach(function(type){ - validityMessages.de.valueMissing[type] = 'Bitte wählen Sie eine Option aus.'; + 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] = '{%value} ist zu früh. {%min} ist die früheste Zeit, die Sie benutzen können.'; + 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] = '{%value} ist zu spät. {%max} ist die späteste Zeit, die Sie benutzen können.'; + 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){ @@ -3574,30 +3340,30 @@ min: 1, max: 1 }; webshims.createValidationMessage = function(elem, name){ - var spinner; + var widget; var message = getMessageFromObj(currentValidationMessage[name], elem); - + var type = $.prop(elem, 'type'); if(!message){ - message = getMessageFromObj(validityMessages[''][name], elem) || 'invalid value'; - webshims.info('could not find errormessage for: '+ name +' / '+ $.prop(elem, 'type') +'. in language: '+$.webshims.activeLang()); + message = getMessageFromObj(validityMessages[''][name], elem) || $.prop(elem, 'validationMessage'); + webshims.info('could not find errormessage for: '+ name +' / '+ type +'. in language: '+$.webshims.activeLang()); } if(message){ ['value', 'min', 'max', 'title', 'maxlength', '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)) || ''; if(name == 'patternMismatch' && attr == 'title' && !val){ webshims.error('no title for patternMismatch provided. Always add a title attribute.'); } if(valueVals[attr]){ - if(!spinner){ - spinner = $(elem).getShadowElement().data('wsspinner'); + if(!widget){ + widget = $(elem).getShadowElement().data('wsWidget'+type); } - if(spinner && spinner.formatValue){ - val = spinner.formatValue(val, false); + if(widget && widget.formatValue){ + val = widget.formatValue(val, false); } } message = message.replace('{%'+ attr +'}', val); if('value' == attr){ message = message.replace('{%valueLen}', val.length); @@ -3608,11 +3374,11 @@ return message || ''; }; - if(webshims.bugs.validationMessage || !Modernizr.formvalidation || webshims.bugs.bustedValidity){ + if(!Modernizr.formvalidation || webshims.bugs.bustedValidity){ implementProperties.push('validationMessage'); } webshims.activeLang({ langObj: validityMessages, @@ -3666,13 +3432,41 @@ }); }); }); }); -jQuery.webshims.register('form-datalist', function($, webshims, window, document, undefined, options){ +webshims.register('form-datalist', function($, webshims, window, document, undefined, options){ "use strict"; - var doc = document; + var doc = document; + 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){ @@ -3704,32 +3498,10 @@ if(listSupport && !formsCFG.customDatalist){return;} var initializeDatalist = function(){ - if(!listSupport){ - webshims.defineNodeNameProperty('datalist', 'options', { - prop: { - writeable: false, - get: function(){ - var elem = this; - var select = $('select', elem); - var options; - if(select[0]){ - options = select[0].options; - } else { - options = $('option', elem).get(); - 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 inputListProto = { //override autocomplete autocomplete: { attr: { get: function(){ @@ -3785,31 +3557,12 @@ } } }; } - if(!listSupport){ - - inputListProto['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(shadowListProto, undefined, {input: elem, id: value, datalist: $.prop(elem, 'list')}); - $(elem).triggerHandler('listdatalistchange'); - } - }, - initAttr: true, - reflect: true, - propType: 'element', - propNodeName: 'datalist' - }; - } else { + + 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, @@ -3825,27 +3578,37 @@ return options; } } }); } - inputListProto['list'] = { + inputListProto.list = { attr: { get: function(){ var val = webshims.contentAttr(this, 'list'); if(val != null){ $.data(this, 'datalistListAttr', val); - this.removeAttribute('list'); + 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); - webshims.objectCreate(shadowListProto, undefined, {input: elem, id: value, datalist: $.prop(elem, 'list')}); + if (!noDatalistSupport[$.prop(this, 'type')] && !noDatalistSupport[$.attr(this, 'type')]) { + webshims.objectCreate(shadowListProto, undefined, { + input: elem, + id: value, + datalist: $.prop(elem, 'list') + }); + } else { + elem.setAttribute('list', value); + } $(elem).triggerHandler('listdatalistchange'); } }, initAttr: true, reflect: true, @@ -3861,73 +3624,26 @@ .filter('datalist > select, datalist, datalist > option, datalist > select > option') .closest('datalist') .each(function(){ $(this).triggerHandler('updateDatalist'); }) - ; - }); - - }; /* * ShadowList */ - var listidIndex = 0; - 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 - }); - } - - var globStoredOptions = {}; - var getStoredOptions = function(name){ - if(!name){return [];} - if(globStoredOptions[name]){ - return globStoredOptions[name]; - } - var data; - try { - data = JSON.parse(localStorage.getItem('storedDatalistOptions'+name)); - } catch(e){} - globStoredOptions[name] = data || []; - return data || []; - }; - var storeOptions = function(name, val){ - if(!name){return;} - val = val || []; - try { - localStorage.setItem( 'storedDatalistOptions'+name, JSON.stringify(val) ); - } catch(e){} - }; - var getText = function(elem){ - return (elem.textContent || elem.innerText || $.text([ elem ]) || ''); - }; - var lReg = /</g; - var gReg = />/g; - 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; @@ -3944,135 +3660,34 @@ } return; } else if(data && data.datalist === datalist){ return; } - listidIndex++; - var that = this; - this.hideList = $.proxy(that, 'hideList'); + + this.datalist = datalist; this.id = opts.id; this.hasViewableData = true; this._autocomplete = $.attr(opts.input, 'autocomplete'); $.data(opts.input, 'datalistWidget', this); - this.popover = webshims.objectCreate(webshims.wsPopover, {}, options.datalistPopover); - this.shadowList = this.popover.element.addClass('datalist-polyfill'); + lazyLoad('WINDOWLOAD'); - - this.index = -1; - this.input = opts.input; - this.arrayOptions = []; - - this.shadowList - .delegate('li', 'mouseenter.datalistWidget mousedown.datalistWidget click.datalistWidget', function(e){ - var items = $('li:not(.hidden-item)', that.shadowList); - var select = (e.type == 'mousedown' || e.type == 'click'); - that.markItem(items.index(e.currentTarget), select, items); - if(e.type == 'click'){ - that.hideList(); - if(formsCFG.customDatalist){ - $(opts.input).getNativeElement().trigger('datalistselect'); - } + if(webshims.isReady('form-datalist-lazy')){ + this._lazyCreate(opts); + } else { + $(opts.input).one('focus', lazyLoad); + webshims.ready('form-datalist-lazy', function(){ + if(!that._destroyed){ + that._lazyCreate(opts); } - return (e.type != 'mousedown'); - }) - ; - - opts.input.setAttribute('autocomplete', 'off'); - - $(opts.input) - .attr({ - //role: 'combobox', - 'aria-haspopup': 'true' - }) - .on({ - 'input.datalistWidget': function(){ - if(!that.triggeredByDatalist){ - that.changedValue = false; - that.showHideOptions(); - } - }, - 'keydown.datalistWidget': function(e){ - var keyCode = e.keyCode; - var activeItem; - var items; - if(keyCode == 40 && !that.showList()){ - that.markItem(that.index + 1, true); - return false; - } - - if(!that.popover.isVisible){return;} - - - if(keyCode == 38){ - that.markItem(that.index - 1, true); - return false; - } - if(!e.shiftKey && (keyCode == 33 || keyCode == 36)){ - that.markItem(0, true); - return false; - } - if(!e.shiftKey && (keyCode == 34 || keyCode == 35)){ - items = $('li:not(.hidden-item)', that.shadowList); - that.markItem(items.length - 1, true, items); - return false; - } - if(keyCode == 13 || keyCode == 27){ - if (keyCode == 13){ - activeItem = $('li.active-item:not(.hidden-item)', that.shadowList); - that.changeValue( $('li.active-item:not(.hidden-item)', that.shadowList) ); - } - that.hideList(); - if(formsCFG.customDatalist && activeItem && activeItem[0]){ - $(opts.input).getNativeElement().trigger('datalistselect'); - } - return false; - } - }, - 'focus.datalistWidget': function(){ - if($(this).hasClass('list-focus')){ - that.showList(); - } - }, - 'mousedown.datalistWidget': function(){ - if($(this).is(':focus')){ - that.showList(); - } - } - }) - ; - - - $(this.datalist) - .off('updateDatalist.datalistWidget') - .on('updateDatalist.datalistWidget', $.proxy(this, '_resetListCached')) - ; - - this._resetListCached(); - - if(opts.input.form && (opts.input.name || opts.input.id)){ - $(opts.input.form).on('submit.datalistWidget'+opts.input.id, function(){ - if(!$(opts.input).hasClass('no-datalist-cache') && that._autocomplete != 'off'){ - var val = $.prop(opts.input, 'value'); - var name = (opts.input.name || opts.input.id) + $.prop(opts.input, 'type'); - if(!that.storedOptions){ - that.storedOptions = getStoredOptions( name ); - } - if(val && that.storedOptions.indexOf(val) == -1){ - that.storedOptions.push(val); - storeOptions(name, that.storedOptions ); - } - } }); } - $(window).on('unload.datalist'+this.id+' beforeunload.datalist'+this.id, function(){ - that.destroy(); - }); }, - destroy: function(){ + destroy: function(e){ + var input; var autocomplete = $.attr(this.input, 'autocomplete'); $(this.input) .off('.datalistWidget') .removeData('datalistWidget') ; @@ -4086,270 +3701,23 @@ if(autocomplete === undefined){ this.input.removeAttribute('autocomplete'); } else { $(this.input).attr('autocomplete', autocomplete); } - }, - _resetListCached: function(e){ - var that = this; - var forceShow; - this.needsUpdate = true; - this.lastUpdatedValue = false; - this.lastUnfoundValue = ''; - - if(!this.updateTimer){ - if(window.QUnit || (forceShow = ($(that.input).is(':focus') && ($(that.input).hasClass('list-focus') || $.prop(that.input, 'value'))) )){ - that.updateListOptions(forceShow); - } else { - webshims.ready('WINDOWLOAD', function(){ - that.updateTimer = setTimeout(function(){ - that.updateListOptions(); - that = null; - listidIndex = 1; - }, 200 + (100 * listidIndex)); - }); - } + if(e && e.type == 'beforeunload'){ + input = this.input; + setTimeout(function(){ + $.attr(input, 'list', $.attr(input, 'list')); + }, 9); } - }, - updateListOptions: function(_forceShow){ - this.needsUpdate = false; - clearTimeout(this.updateTimer); - this.updateTimer = false; - - this.searchStart = formsCFG.customDatalist && $(this.input).hasClass('search-start'); - this.addMarkElement = options.addMark || $(this.input).hasClass('mark-option-text'); - - var list = []; - - var values = []; - var allOptions = []; - var rElem, rItem, rOptions, rI, rLen, item, value; - for(rOptions = $.prop(this.datalist, 'options'), rI = 0, rLen = rOptions.length; rI < rLen; rI++){ - rElem = rOptions[rI]; - if(!rElem.disabled && (value = $(rElem).val())){ - rItem = { - value: value.replace(lReg, '&lt;').replace(gReg, '&gt;'), - label: $.trim($.attr(rElem, 'label') || getText(rElem)).replace(lReg, '&lt;').replace(gReg, '&gt;'), - className: rElem.className || '' - }; - - if(rItem.label){ - rItem.className += ' has-option-label'; - } - values.push(rItem.value); - allOptions.push(rItem); - } - } - - if(!this.storedOptions){ - this.storedOptions = ($(this.input).hasClass('no-datalist-cache') || this._autocomplete == 'off') ? [] : getStoredOptions((this.input.name || this.input.id) + $.prop(this.input, 'type')); - } - - this.storedOptions.forEach(function(val, i){ - if(values.indexOf(val) == -1){ - allOptions.push({value: val, label: '', className: 'stored-suggest', style: ''}); - } - }); - - for(rI = 0, rLen = allOptions.length; rI < rLen; rI++){ - item = allOptions[rI]; - list[rI] = '<li class="'+ item.className +'" tabindex="-1" role="listitem">'+ this.getOptionContent(item) +'</li>'; - } - - this.arrayOptions = allOptions; - this.popover.contentElement.html('<div class="datalist-box"><ul role="list">'+ list.join("\n") +'</ul></div>'); - - - if(_forceShow || this.popover.isVisible){ - this.showHideOptions(); - } - }, - getOptionContent: function(item){ - var content = ''; - if(options.getOptionContent){ - content = options.apply(this, arguments) || ''; - } else { - content = '<span class="option-value">'+ item.value +'</span>'; - if(item.label){ - content += ' <span class="option-label">'+ item.label +'</span>'; - } - } - return content; - }, - showHideOptions: function(_fromShowList){ - var value = $.prop(this.input, 'value').toLowerCase(); - - //first check prevent infinite loop, second creates simple lazy optimization - if(value === this.lastUpdatedValue){ - return; - } - if(this.lastUnfoundValue && value.indexOf(this.lastUnfoundValue) === 0){ - this.hideList(); - return; - } - - - this.lastUpdatedValue = value; - var found = false; - var startSearch = this.searchStart; - var lis = $('li', this.shadowList); - var that = this; - if(value){ - - this.arrayOptions.forEach(function(item, i){ - var search, searchIndex, foundName; - if(!('lowerValue' in item)){ - item.lowerValue = item.value.toLowerCase(); - if(item.label && item.label != item.value ){ - item.lowerLabel = item.label.toLowerCase(); - } - } - - if(value != item.lowerValue && item.lowerLabel != value){ - searchIndex = item.lowerValue.indexOf(value); - search = startSearch ? !searchIndex : searchIndex !== -1; - if(search){ - foundName = 'value'; - } else if(item.lowerLabel){ - searchIndex = item.lowerLabel.indexOf(value); - search = startSearch ? !searchIndex : searchIndex !== -1; - foundName = 'label'; - } - } - - if(search){ - that.addMark($(lis[i]).removeClass('hidden-item'), item, foundName, searchIndex, value.length); - found = true; - } else { - $(lis[i]).addClass('hidden-item'); - } - }); - } else if(lis.length) { - this.removeMark(lis.removeClass('hidden-item')); - found = true; - } - - this.hasViewableData = found; - if(!_fromShowList && found){ - this.showList(); - } - - if(!found){ - this.lastUnfoundValue = value; - this.hideList(); - } else { - this.lastUnfoundValue = false; - } - }, - otherType: { - value: 'label', - label: 'value' - }, - addMark: function(elem, item, prop, start, length){ - if(this.addMarkElement){ - var text = item[prop].substr(start, length); - text = item[prop].replace(text ,'<mark>'+ text +'</mark>'); - $('.option-'+ this.otherType[prop] +' > mark', elem).each(this._replaceMark); - $('.option-'+prop, elem).html(text); - - } - }, - _replaceMark: function(){ - var content = $(this).html(); - $(this).replaceWith(content); - }, - removeMark: function(lis){ - if(this.addMarkElement){ - $('mark', lis).each(this._replaceMark); - } - }, - showList: function(){ - if(this.popover.isVisible){return false;} - if(this.needsUpdate){ - this.updateListOptions(); - } - this.showHideOptions(true); - if(!this.hasViewableData){return false;} - var that = this; - - that.shadowList.find('li.active-item').removeClass('active-item'); - that.popover.show(this.input); - - - return true; - }, - hideList: function(){ - if(!this.popover.isVisible){return false;} - var that = this; - - - this.popover.hide(); - that.shadowList.removeClass('datalist-visible list-item-active'); - that.index = -1; - if(that.changedValue){ - that.triggeredByDatalist = true; - $(that.input).trigger('input').trigger('change'); - that.changedValue = false; - that.triggeredByDatalist = false; - } - - return true; - }, - scrollIntoView: function(elem){ - var ul = $('ul', this.shadowList); - var div = $('div.datalist-box', this.shadowList); - var elemPos = elem.position(); - var containerHeight; - elemPos.top -= (parseInt(ul.css('paddingTop'), 10) || 0) + (parseInt(ul.css('marginTop'), 10) || 0) + (parseInt(ul.css('borderTopWidth'), 10) || 0); - if(elemPos.top < 0){ - div.scrollTop( div.scrollTop() + elemPos.top - 2); - return; - } - elemPos.top += elem.outerHeight(); - containerHeight = div.height(); - if(elemPos.top > containerHeight){ - div.scrollTop( div.scrollTop() + (elemPos.top - containerHeight) + 2); - } - }, - changeValue: function(activeItem){ - if(!activeItem[0]){return;} - var spinner; - var newValue = $('span.option-value', activeItem).text(); - var oldValue = $.prop(this.input, 'value'); - if(newValue != oldValue){ - - $(this.input) - .prop('value', newValue) - .triggerHandler('updateInput') - ; - this.changedValue = true; - if((spinner = $.data(this.input, 'wsspinner')) && spinner.setInput){ - spinner.setInput(newValue); - } - } - }, - markItem: function(index, doValue, items){ - var activeItem; - var goesUp; - - items = items || $('li:not(.hidden-item)', this.shadowList); - if(!items.length){return;} - if(index < 0){ - index = items.length - 1; - } else if(index >= items.length){ - index = 0; - } - items.removeClass('active-item'); - this.shadowList.addClass('list-item-active'); - activeItem = items.filter(':eq('+ index +')').addClass('active-item'); - - if(doValue){ - this.changeValue(activeItem); - this.scrollIntoView(activeItem); - } - this.index = index; + this._destroyed = true; } }; + + webshims.loader.addModule('form-datalist-lazy', { + noAutoCallback: true, + options: $.extend(options, {shadowListProto: shadowListProto}) + }); //init datalist update initializeDatalist(); })(); \ No newline at end of file