vendor/assets/javascripts/webshims/shims/combos/11.js in webshims-rails-0.4.7 vs vendor/assets/javascripts/webshims/shims/combos/11.js in webshims-rails-1.10.3

- old
+ new

@@ -1,1635 +1,2611 @@ -//DOM-Extension helper -jQuery.webshims.register('dom-extend', function($, webshims, window, document, undefined){ - "use strict"; - //shortcus - var modules = webshims.modules; - var listReg = /\s*,\s*/; - - //proxying attribute - var olds = {}; - var havePolyfill = {}; - var extendedProps = {}; - var extendQ = {}; - var modifyProps = {}; +(function($){ - var oldVal = $.fn.val; - var singleVal = function(elem, name, val, pass, _argless){ - return (_argless) ? oldVal.call($(elem)) : oldVal.call($(elem), val); + var id = 0; + var isNumber = function(string){ + return (typeof string == 'number' || (string && string == string * 1)); }; - - $.fn.onTrigger = function(evt, fn){ - return this.on(evt, fn).each(fn); - }; - - $.fn.val = function(val){ - var elem = this[0]; - if(arguments.length && val == null){ - val = ''; + var retDefault = function(val, def){ + if(!(typeof val == 'number' || (val && val == val * 1))){ + return def; } - if(!arguments.length){ - if(!elem || elem.nodeType !== 1){return oldVal.call(this);} - return $.prop(elem, 'value', val, 'val', true); - } - if($.isArray(val)){ - return oldVal.apply(this, arguments); - } - var isFunction = $.isFunction(val); - return this.each(function(i){ - elem = this; - if(elem.nodeType === 1){ - if(isFunction){ - var genVal = val.call( elem, i, $.prop(elem, 'value', undefined, 'val', true)); - if(genVal == null){ - genVal = ''; - } - $.prop(elem, 'value', genVal, 'val') ; - } else { - $.prop(elem, 'value', val, 'val'); - } - } - }); + return val * 1; }; - - 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); - if(val !== undefined){ - if(!data){ - data = $.data(elem, dataID, {}); - } - if(key){ - data[key] = val; - } - } - - return key ? data && data[key] : data; - }; - - - [{name: 'getNativeElement', prop: 'nativeElement'}, {name: 'getShadowElement', prop: 'shadowElement'}, {name: 'getShadowFocusElement', prop: 'shadowFocusElement'}].forEach(function(data){ - $.fn[data.name] = function(){ - return this.map(function(){ - var shadowData = elementData(this, 'shadowData'); - return shadowData && shadowData[data.prop] || this; - }); - }; - }); - - - ['removeAttr', 'prop', 'attr'].forEach(function(type){ - olds[type] = $[type]; - $[type] = function(elem, name, value, pass, _argless){ - var isVal = (pass == 'val'); - var oldMethod = !isVal ? olds[type] : singleVal; - if( !elem || !havePolyfill[name] || elem.nodeType !== 1 || (!isVal && pass && type == 'attr' && $.attrFn[name]) ){ - return oldMethod(elem, name, value, pass, _argless); - } + var createOpts = ['step', 'min', 'max', 'readonly', 'title', 'disabled', 'tabindex']; + var rangeProto = { + _create: function(){ + var i; - var nodeName = (elem.nodeName || '').toLowerCase(); - var desc = extendedProps[nodeName]; - var curType = (type == 'attr' && (value === false || value === null)) ? 'removeAttr' : type; - var propMethod; - var oldValMethod; - var ret; + this.element.addClass('ws-range').attr({role: 'slider'}).append('<span class="ws-range-min" /><span class="ws-range-rail"><span class="ws-range-thumb" /></span>'); + this.trail = $('.ws-range-rail', this.element); + this.range = $('.ws-range-min', this.element); + this.thumb = $('.ws-range-thumb', this.trail); - if(!desc){ - desc = extendedProps['*']; + this.updateMetrics(); + + this.orig = this.options.orig; + + for(i = 0; i < createOpts.length; i++){ + this[createOpts[i]](this.options[createOpts[i]]); } - if(desc){ - desc = desc[name]; + this.value = this._value; + this.value(this.options.value); + this.initDataList(); + this.element.data('rangeUi', this); + this.addBindings(); + this._init = true; + }, + value: $.noop, + _value: function(val, _noNormalize, animate){ + var left, posDif; + var o = this.options; + var oVal = val; + var thumbStyle = {}; + var rangeStyle = {}; + if(!_noNormalize && parseFloat(val, 10) != val){ + val = o.min + ((o.max - o.min) / 2); } - if(desc){ - propMethod = desc[curType]; + if(!_noNormalize){ + val = this.normalizeVal(val); } + left = 100 * ((val - o.min) / (o.max - o.min)); - if(propMethod){ - if(name == 'value'){ - oldValMethod = propMethod.isVal; - propMethod.isVal = isVal; + this.options.value = val; + this.thumb.stop(); + this.range.stop(); + + rangeStyle[this.dirs.width] = left+'%'; + if(this.vertical){ + left = Math.abs(left - 100); + } + thumbStyle[this.dirs.left] = left+'%'; + + + if(!animate){ + this.thumb.css(thumbStyle); + this.range.css(rangeStyle); + } else { + if(typeof animate != 'object'){ + animate = {}; + } else { + animate = $.extend({}, animate); } - if(curType === 'removeAttr'){ - return propMethod.value.call(elem); - } else if(value === undefined){ - return (propMethod.get) ? - propMethod.get.call(elem) : - propMethod.value + if(!animate.duration){ + posDif = Math.abs(left - parseInt(this.thumb[0].style[this.dirs.left] || 50, 10)); + animate.duration = Math.max(Math.min(999, posDif * 5), 99); + } + this.thumb.animate(thumbStyle, animate); + this.range.animate(rangeStyle, animate); + } + if(this.orig && (oVal != val || (!this._init && this.orig.value != val)) ){ + this.options._change(val); + } + this.element.attr({ + 'aria-valuenow': this.options.value, + 'aria-valuetext': this.options.textValue ? this.options.textValue(this.options.value) : this.options.options[this.options.value] || this.options.value + }); + }, + initDataList: function(){ + if(this.orig){ + var listTimer; + var that = this; + var updateList = function(){ + $(that.orig) + .jProp('list') + .off('updateDatalist', updateList) + .on('updateDatalist', updateList) ; - } else if(propMethod.set) { - if(type == 'attr' && value === true){ - value = name; - } + clearTimeout(listTimer); + listTimer = setTimeout(function(){ + if(that.list){ + that.list(); + } + }, 9); - ret = propMethod.set.call(elem, value); + }; + + $(this.orig).on('listdatalistchange', updateList); + this.list(); + } + }, + list: function(opts){ + var o = this.options; + var min = o.min; + var max = o.max; + var trail = this.trail; + var that = this; + + this.element.attr({'aria-valuetext': o.options[o.value] || o.value}); + $('.ws-range-ticks', trail).remove(); + + + $(this.orig).jProp('list').find('option').each(function(){ + o.options[$.prop(this, 'value')] = $.prop(this, 'label'); + }); + + $.each(o.options, function(val, label){ + if(!isNumber(val) || val < min || val > max){return;} + var left = 100 * ((val - min) / (max - min)); + var title = o.showLabels ? ' title="'+ label +'"' : ''; + if(that.vertical){ + left = Math.abs(left - 100); } - if(name == 'value'){ - propMethod.isVal = oldValMethod; - } + trail.append('<span class="ws-range-ticks"'+ title +' style="'+(that.dirs.left)+': '+left+'%;" />'); + }); + }, + readonly: function(val){ + val = !!val; + this.options.readonly = val; + this.element.attr('aria-readonly', ''+val); + }, + disabled: function(val){ + val = !!val; + this.options.disabled = val; + if(val){ + this.element.attr({tabindex: -1, 'aria-disabled': 'true'}); } else { - ret = oldMethod(elem, name, value, pass, _argless); + this.element.attr({tabindex: this.options.tabindex, 'aria-disabled': 'false'}); } - if((value !== undefined || curType === 'removeAttr') && modifyProps[nodeName] && modifyProps[nodeName][name]){ - - var boolValue; - if(curType == 'removeAttr'){ - boolValue = false; - } else if(curType == 'prop'){ - boolValue = !!(value); - } else { - boolValue = true; - } - - modifyProps[nodeName][name].forEach(function(fn){ - if(!fn.only || (fn.only = 'prop' && type == 'prop') || (fn.only == 'attr' && type != 'prop')){ - fn.call(elem, value, boolValue, (isVal) ? 'val' : curType, type); - } - }); + }, + tabindex: function(val){ + this.options.tabindex = val; + if(!this.options.disabled){ + this.element.attr({tabindex: val}); } - return ret; - }; + }, + title: function(val){ + this.element.prop('title', val); + }, + min: function(val){ + this.options.min = retDefault(val, 0); + this.value(this.options.value, true); + }, + max: function(val){ + this.options.max = retDefault(val, 100); + this.value(this.options.value, true); + }, + step: function(val){ + this.options.step = val == 'any' ? 'any' : retDefault(val, 1); + this.value(this.options.value); + }, - extendQ[type] = function(nodeName, prop, desc){ + normalizeVal: function(val){ + var valModStep, alignValue, step; + var o = this.options; - if(!extendedProps[nodeName]){ - extendedProps[nodeName] = {}; + if(val <= o.min){ + val = o.min; + } else if(val >= o.max) { + val = o.max; + } else if(o.step != 'any'){ + step = o.step; + valModStep = (val - o.min) % step; + alignValue = val - valModStep; + + if ( Math.abs(valModStep) * 2 >= step ) { + alignValue += ( valModStep > 0 ) ? step : ( -step ); + } + val = alignValue.toFixed(5) * 1; } - if(!extendedProps[nodeName][prop]){ - extendedProps[nodeName][prop] = {}; + return val; + }, + doStep: function(factor, animate){ + var step = retDefault(this.options.step, 1); + if(this.options.step == 'any'){ + step = Math.min(step, (this.options.max - this.options.min) / 10); } - var oldDesc = extendedProps[nodeName][prop][type]; - var getSup = function(propType, descriptor, oDesc){ - if(descriptor && descriptor[propType]){ - return descriptor[propType]; + this.value( this.options.value + (step * factor), false, animate ); + + }, + + getStepedValueFromPos: function(pos){ + var val, valModStep, alignValue, step; + + if(pos <= 0){ + val = this.options[this.dirs.min]; + } else if(pos > 100) { + val = this.options[this.dirs.max]; + } else { + if(this.vertical){ + pos = Math.abs(pos - 100); } - if(oDesc && oDesc[propType]){ - return oDesc[propType]; + val = ((this.options.max - this.options.min) * (pos / 100)) + this.options.min; + step = this.options.step; + if(step != 'any'){ + valModStep = (val - this.options.min) % step; + alignValue = val - valModStep; + + if ( Math.abs(valModStep) * 2 >= step ) { + alignValue += ( valModStep > 0 ) ? step : ( -step ); + } + val = ((alignValue).toFixed(5)) * 1; + } - if(type == 'prop' && prop == 'value'){ - return function(value){ - var elem = this; - return (desc.isVal) ? - singleVal(elem, prop, value, false, (arguments.length === 0)) : - olds[type](elem, prop, value) - ; - }; + } + + return val; + }, + addBindings: function(){ + var leftOffset, widgetUnits, hasFocus; + var that = this; + var o = this.options; + + var eventTimer = (function(){ + var events = {}; + return { + init: function(name, curVal, fn){ + if(!events[name]){ + events[name] = {fn: fn}; + if(that.orig){ + $(that.orig).on(name, function(){ + events[name].val = $.prop(that.orig, 'value'); + }); + } + + } + events[name].val = curVal; + }, + call: function(name, val){ + if(events[name].val != val){ + clearTimeout(events[name].timer); + events[name].val = val; + events[name].timer = setTimeout(function(){ + events[name].fn(val, that); + }, 0); + } + } + }; + })(); + + var setValueFromPos = function(e, animate){ + + var val = that.getStepedValueFromPos((e[that.dirs.mouse] - leftOffset) * widgetUnits); + if(val != o.value){ + that.value(val, false, animate); + eventTimer.call('input', val); } - if(type == 'prop' && propType == 'value' && desc.value.apply){ - return function(value){ - var sup = olds[type](this, prop); - if(sup && sup.apply){ - sup = sup.apply(this, arguments); - } - return sup; - }; + }; + + var remove = function(e){ + if(e && e.type == 'mouseup'){ + eventTimer.call('input', o.value); + eventTimer.call('change', o.value); } - return function(value){ - return olds[type](this, prop, value); - }; + that.element.removeClass('ws-active'); + $(document).off('mousemove', setValueFromPos).off('mouseup', remove); }; - extendedProps[nodeName][prop][type] = desc; - if(desc.value === undefined){ - if(!desc.set){ - desc.set = desc.writeable ? - getSup('set', desc, oldDesc) : - (webshims.cfg.useStrict && prop == 'prop') ? - function(){throw(prop +' is readonly on '+ nodeName);} : - $.noop + var add = function(e){ + e.preventDefault(); + $(document).off('mousemove', setValueFromPos).off('mouseup', remove); + if(!o.readonly && !o.disabled){ + leftOffset = that.element.focus().addClass('ws-active').offset(); + widgetUnits = that.element[that.dirs.width](); + if(!widgetUnits || !leftOffset){return;} + leftOffset = leftOffset[that.dirs.pos]; + widgetUnits = 100 / (widgetUnits - ((that.thumb[that.dirs.outerWidth]() || 2) / 2)); + setValueFromPos(e, o.animate); + $(document) + .on({ + mouseup: remove, + mousemove: setValueFromPos + }) ; + e.stopPropagation(); } - if(!desc.get){ - desc.get = getSup('get', desc, oldDesc); - } + }; + var elementEvts = { + mousedown: add, + focus: function(e){ + if(!o.disabled){ + eventTimer.init('input', o.value); + eventTimer.init('change', o.value); + that.element.addClass('ws-focus'); + } + hasFocus = true; + }, + blur: function(e){ + that.element.removeClass('ws-focus ws-active'); + hasFocus = false; + eventTimer.init('input', o.value); + eventTimer.call('change', o.value); + }, + keyup: function(){ + that.element.removeClass('ws-active'); + eventTimer.call('input', o.value); + eventTimer.call('change', o.value); + }, - } + keydown: function(e){ + var step = true; + var code = e.keyCode; + if(!o.readonly && !o.disabled){ + if (code == 39 || code == 38) { + that.doStep(1); + } else if (code == 37 || code == 40) { + that.doStep(-1); + } else if (code == 33) { + that.doStep(10, o.animate); + } else if (code == 34) { + that.doStep(-10, o.animate); + } else if (code == 36) { + that.value(that.options.max, false, o.animate); + } else if (code == 35) { + that.value(that.options.min, false, o.animate); + } else { + step = false; + } + if (step) { + that.element.addClass('ws-active'); + eventTimer.call('input', o.value); + e.preventDefault(); + } + } + } + }; - ['value', 'get', 'set'].forEach(function(descProp){ - if(desc[descProp]){ - desc['_sup'+descProp] = getSup(descProp, oldDesc); + eventTimer.init('input', o.value, this.options.input); + eventTimer.init('change', o.value, this.options.change); + + elementEvts[$.fn.mwheelIntent ? 'mwheelIntent' : 'mousewheel'] = function(e, delta){ + if(delta && hasFocus && !o.readonly && !o.disabled){ + that.doStep(delta); + e.preventDefault(); + eventTimer.call('input', o.value); } + }; + this.element.on(elementEvts); + this.thumb.on({ + mousedown: add }); - }; - - }); + }, + updateMetrics: function(){ + var width = this.element.innerWidth(); + this.vertical = (width && this.element.innerHeight() - width > 10); + + this.dirs = this.vertical ? + {mouse: 'pageY', pos: 'top', min: 'max', max: 'min', left: 'top', width: 'height', outerWidth: 'outerHeight'} : + {mouse: 'pageX', pos: 'left', min: 'min', max: 'max', left: 'left', width: 'width', outerWidth: 'outerWidth'} + ; + this.element + [this.vertical ? 'addClass' : 'removeClass']('vertical-range') + [this.vertical ? 'addClass' : 'removeClass']('horizontal-range') + ; + } + }; - //see also: https://github.com/lojjic/PIE/issues/40 | https://prototype.lighthouseapp.com/projects/8886/tickets/1107-ie8-fatal-crash-when-prototypejs-is-loaded-with-rounded-cornershtc - var isExtendNativeSave = Modernizr.ES5; - var extendNativeValue = (function(){ - var UNKNOWN = webshims.getPrototypeOf(document.createElement('foobar')); - var has = Object.prototype.hasOwnProperty; - return function(nodeName, prop, desc){ - var elem; - var elemProto; - if( isExtendNativeSave && (elem = document.createElement(nodeName)) && (elemProto = webshims.getPrototypeOf(elem)) && UNKNOWN !== elemProto && ( !elem[prop] || !has.call(elem, prop) ) ){ - var sup = elem[prop]; - desc._supvalue = function(){ - if(sup && sup.apply){ - return sup.apply(this, arguments); - } - return sup; + $.fn.rangeUI = function(opts){ + opts = $.extend({readonly: false, disabled: false, tabindex: 0, min: 0, step: 1, max: 100, value: 50, input: $.noop, change: $.noop, _change: $.noop, showLabels: true, options: {}}, opts); + return this.each(function(){ + $.webshims.objectCreate(rangeProto, { + element: { + value: $(this) + } + }, opts); + }); + }; + jQuery.webshims.isReady('range-ui', true); +})(jQuery); +jQuery.webshims.register('form-number-date-ui', function($, webshims, window, document, undefined, options){ + "use strict"; + var curCfg; + var formcfg = $.webshims.formcfg; + + var stopPropagation = function(e){ + e.stopImmediatePropagation(e); + }; + var createFormat = function(name){ + if(!curCfg.patterns[name+'Obj']){ + var obj = {}; + $.each(curCfg.patterns[name].split(curCfg[name+'Format']), function(i, name){ + obj[name] = i; + }); + curCfg.patterns[name+'Obj'] = obj; + } + }; + var splitInputs = { + date: { + _create: function(){ + var obj = { + splits: [$('<input type="text" class="yy" size="4" maxlength />')[0], $('<input type="text" class="mm" maxlength="2" size="2" />')[0], $('<input type="text" class="dd ws-spin" maxlength="2" size="2" />')[0]] }; - elemProto[prop] = desc.value; - } else { - desc._supvalue = function(){ - var data = elementData(this, 'propValue'); - if(data && data[prop] && data[prop].apply){ - return data[prop].apply(this, arguments); + obj.elements = [obj.splits[0], $('<span class="ws-input-seperator" />')[0], obj.splits[1], $('<span class="ws-input-seperator" />')[0], obj.splits[2]]; + return obj; + }, + sort: function(element){ + createFormat('d'); + var i = 0; + var seperators = $('.ws-input-seperator', element).html(curCfg.dFormat); + var inputs = $('input', element); + $.each(curCfg.patterns.dObj, function(name, value){ + var input = inputs.filter('.'+ name); + if(input[0]){ + + input.appendTo(element); + if(i < seperators.length){ + seperators.eq(i).insertAfter(input); + } + i++; } - return data && data[prop]; + }); + } + }, + month: { + _create: function(){ + var obj = { + splits: [$('<input type="text" class="yy" size="4" />')[0], $('<input type="text" class="mm ws-spin" />')[0]] }; - initProp.extendValue(nodeName, prop, desc.value); + obj.elements = [obj.splits[0], $('<span class="ws-input-seperator" />')[0], obj.splits[1]]; + return obj; + }, + sort: function(element){ + var seperator = $('.ws-input-seperator', element).html(curCfg.dFormat); + var mm = $('input.mm', element); + var action; + if(curCfg.date.showMonthAfterYear){ + mm.appendTo(element); + action = 'insertBefore'; + } else { + mm.prependTo(element); + action = 'insertAfter'; + } + seperator[action](mm); } - desc.value._supvalue = desc._supvalue; + } + }; + var labelWidth = (function(){ + var getId = function(){ + return webshims.getID(this); }; + return function(element, labels, noFocus){ + $(element).attr({'aria-labelledby': labels.map(getId).get().join(' ')}); + if(!noFocus){ + labels.on('click', function(e){ + element.getShadowFocusElement().focus(); + e.preventDefault(); + return false; + }); + } + }; })(); + var addZero = function(val){ + if(!val){return "";} + val = val+''; + return val.length == 1 ? '0'+val : val; + }; + - var initProp = (function(){ + (function(){ + var monthDigits = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12']; + formcfg.de = { + numberFormat: { + ",": ".", + ".": "," + }, + timeSigns: ":. ", + numberSigns: ',', + dateSigns: '.', + dFormat: ".", + patterns: { + d: "dd.mm.yy" + }, + month: { + currentText: 'Aktueller Monat' + }, + date: { + close: 'schließen', + clear: 'Löschen', + prevText: 'Zurück', + nextText: 'Vor', + currentText: 'Heute', + monthNames: ['Januar','Februar','März','April','Mai','Juni', + 'Juli','August','September','Oktober','November','Dezember'], + monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dez'], + dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'], + dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'], + dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'], + weekHeader: 'KW', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: '' + } + }; - var initProps = {}; + formcfg.en = { + numberFormat: { + ".": ".", + ",": "," + }, + numberSigns: '.', + dateSigns: '/', + timeSigns: ":. ", + dFormat: "/", + patterns: { + d: "mm/dd/yy" + }, + month: { + currentText: 'This month' + }, + date: { + "closeText": "Done", + clear: 'Clear', + "prevText": "Prev", + "nextText": "Next", + "currentText": "Today", + "monthNames": ["January","February","March","April","May","June","July","August","September","October","November","December"], + "monthNamesShort": ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"], + "dayNames": ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"], + "dayNamesShort": ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"], + "dayNamesMin": ["Su","Mo","Tu","We","Th","Fr","Sa"], + "weekHeader": "Wk", + "firstDay": 0, + "isRTL": false, + "showMonthAfterYear": false, + "yearSuffix": "" + } + }; - webshims.addReady(function(context, contextElem){ - var nodeNameCache = {}; - var getElementsByName = function(name){ - if(!nodeNameCache[name]){ - nodeNameCache[name] = $(context.getElementsByTagName(name)); - if(contextElem[0] && $.nodeName(contextElem[0], name)){ - nodeNameCache[name] = nodeNameCache[name].add(contextElem); - } + formcfg['en-US'] = formcfg['en-US'] || formcfg['en']; + formcfg[''] = formcfg[''] || formcfg['en-US']; + curCfg = formcfg['']; + + var createMonthKeys = function(langCfg){ + if(!langCfg.date.monthkeys){ + var create = function(i, name){ + var strNum; + var num = i + 1; + strNum = (num < 10) ? '0'+num : ''+num; + langCfg.date.monthkeys[num] = strNum; + langCfg.date.monthkeys[name] = strNum; + langCfg.date.monthkeys[name.toLowerCase()] = strNum; + }; + langCfg.date.monthkeys = {}; + langCfg.date.monthDigits = monthDigits; + langCfg.numberSigns += '-'; + $.each(langCfg.date.monthNames, create); + $.each(langCfg.date.monthNamesShort, create); + } + }; + + createMonthKeys(curCfg); + + $.webshims.ready('dom-extend', function(){ + $.webshims.activeLang({ + register: 'form-core', + callback: function(){ + $.each(arguments, function(i, val){ + if(formcfg[val]){ + curCfg = formcfg[val]; + createMonthKeys(curCfg); + $(document).triggerHandler('wslocalechange'); + return false; + } + }); } - }; - - - $.each(initProps, function(name, fns){ - getElementsByName(name); - if(!fns || !fns.forEach){ - webshims.warn('Error: with '+ name +'-property. methods: '+ fns); - return; - } - fns.forEach(function(fn){ - nodeNameCache[name].each(fn); - }); }); - nodeNameCache = null; }); + })(); - var tempCache; - var emptyQ = $([]); - var createNodeNameInit = function(nodeName, fn){ - if(!initProps[nodeName]){ - initProps[nodeName] = [fn]; - } else { - initProps[nodeName].push(fn); + + + (function(){ + + + var mousePress = function(e){ + $(this)[e.type == 'mousepressstart' ? 'addClass' : 'removeClass']('mousepress-ui'); + }; + + var retDefault = function(val, def){ + if(!(typeof val == 'number' || (val && val == val * 1))){ + return def; } - if($.isDOMReady){ - (tempCache || $( document.getElementsByTagName(nodeName) )).each(fn); - } + return val * 1; }; - var elementExtends = {}; - return { - createTmpCache: function(nodeName){ - if($.isDOMReady){ - tempCache = tempCache || $( document.getElementsByTagName(nodeName) ); + var createOpts = ['step', 'min', 'max', 'readonly', 'title', 'disabled', 'tabindex', 'placeholder', 'value']; + + + var formatVal = { + number: function(val){ + return (val+'').replace(/\,/g, '').replace(/\./, curCfg.numberFormat['.']); + }, + time: function(val){ + return val; + }, + //todo empty val for month/split + month: function(val, options){ + var names; + var p = val.split('-'); + if(p[0] && p[1]){ + names = curCfg.date[options.formatMonthNames] || curCfg.date[options.monthNames] || curCfg.date.monthNames; + p[1] = names[(p[1] * 1) - 1]; + if(options && options.splitInput){ + val = [p[0] || '', p[1] || '']; + } else if(p[1]){ + val = curCfg.date.showMonthAfterYear ? p.join(' ') : p[1]+' '+p[0]; + } } - return tempCache || emptyQ; + return val; }, - flushTmpCache: function(){ - tempCache = null; + date: function(val, opts){ + var p = (val+'').split('-'); + if(p[2] && p[1] && p[0]){ + if(opts && opts.splitInput){ + val = p; + } else { + val = curCfg.patterns.d.replace('yy', p[0] || ''); + val = val.replace('mm', p[1] || ''); + val = val.replace('dd', p[2] || ''); + } + } else if(opts && opts.splitInput){ + val = [p[0] || '', p[1] || '', p[2] || '']; + } + + return val; + } + }; + + var parseVal = { + number: function(val){ + return (val+'').replace(curCfg.numberFormat[','], '').replace(curCfg.numberFormat['.'], '.'); }, - content: function(nodeName, prop){ - createNodeNameInit(nodeName, function(){ - var val = $.attr(this, prop); - if(val != null){ - $.attr(this, prop, val); + time: function(val){ + return val; + }, + month: function(val, opts){ + + var p = (!opts.splitInput) ? val.trim().split(/[\.\s-\/\\]+/) : val; + + if(p.length == 2){ + p[0] = curCfg.date.monthkeys[p[0]] || p[0]; + p[1] = curCfg.date.monthkeys[p[1]] || p[1]; + if(p[1].length == 2){ + val = p[0]+'-'+p[1]; + } else if(p[0].length == 2){ + val = p[1]+'-'+p[0]; + } else { + val = ''; } - }); + } else if(opts.splitInput) { + val = ''; + } + return val; }, - createElement: function(nodeName, fn){ - createNodeNameInit(nodeName, fn); + date: function(val, opts){ + createFormat('d'); + var i; + var obj; + if(opts.splitInput){ + obj = {yy: 0, mm: 1, dd: 2}; + } else { + obj = curCfg.patterns.dObj; + val = val.split(curCfg.dFormat); + } + + return (val.length == 3 && val[0] && val[1] && val[2]) ? + ([addZero(val[obj.yy]), addZero(val[obj.mm]), addZero(val[obj.dd])]).join('-') : + '' + ; + } + }; + + var steps = { + number: { + step: 1 }, - extendValue: function(nodeName, prop, value){ - createNodeNameInit(nodeName, function(){ - $(this).each(function(){ - var data = elementData(this, 'propValue', {}); - data[prop] = this[prop]; - this[prop] = value; - }); - }); + time: { + step: 60 + }, + month: { + step: 1, + start: new Date() + }, + date: { + step: 1, + start: new Date() } }; - })(); - var createPropDefault = function(descs, removeType){ - if(descs.defaultValue === undefined){ - descs.defaultValue = ''; - } - if(!descs.removeAttr){ - descs.removeAttr = { - value: function(){ - descs[removeType || 'prop'].set.call(this, descs.defaultValue); - descs.removeAttr._supvalue.call(this); + + var placeholderFormat = { + date: function(val, opts){ + var hintValue = (val || '').split('-'); + if(hintValue.length == 3){ + hintValue = opts.splitInput ? + hintValue : + curCfg.patterns.d.replace('yy', hintValue[0]).replace('mm', hintValue[1]).replace('dd', hintValue[2]); + } else { + hintValue = opts.splitInput ? + [val, val, val] : + val; } - }; - } - if(!descs.attr){ - descs.attr = {}; - } - }; - - $.extend(webshims, { - - getID: (function(){ - var ID = new Date().getTime(); - return function(elem){ - elem = $(elem); - var id = elem.attr('id'); - if(!id){ - ID++; - id = 'ID-'+ ID; - elem.attr('id', id); + return hintValue; + }, + month: function(val, opts){ + var hintValue = (val || '').split('-'); + + if(hintValue.length == 2){ + hintValue = opts.splitInput ? + hintValue : + curCfg.patterns.d.replace('yy', hintValue[0]).replace('mm', hintValue[1]); + } else { + hintValue = opts.splitInput ? + [val, val] : + val; } - return id; + return hintValue; + } + }; + + var createHelper = (function(){ + var types = {}; + return function(type){ + var input; + if(!types[type]){ + input = $('<input type="'+type+'" />'); + types[type] = { + asNumber: function(val){ + var type = (typeof val == 'object') ? 'valueAsDate' : 'value'; + return input.prop(type, val).prop('valueAsNumber'); + }, + asValue: function(val){ + var type = (typeof val == 'object') ? 'valueAsDate' : 'valueAsNumber'; + return input.prop(type, val).prop('value'); + } + }; + } + return types[type]; }; - })(), - extendUNDEFProp: function(obj, props){ - $.each(props, function(name, prop){ - if( !(name in obj) ){ - obj[name] = prop; + })(); + + steps.range = steps.number; + + + var spinBtnProto = { + _create: function(){ + var i; + var o = this.options; + var helper = createHelper(o.type); + this.type = o.type; + this.orig = o.orig; + + this.elemHelper = $('<input type="'+ this.type+'" />'); + this.asNumber = helper.asNumber; + this.asValue = helper.asValue; + + this.buttonWrapper = $('<span class="input-buttons '+this.type+'-input-buttons"><span unselectable="on" class="step-controls"><span class="step-up"></span><span class="step-down"></span></span></span>') + .insertAfter(this.element) + ; + + if(o.splitInput){ + this._addSplitInputs(); + } else { + this.inputElements = this.element; } - }); - }, - //http://www.w3.org/TR/html5/common-dom-interfaces.html#reflect - createPropDefault: createPropDefault, - data: elementData, - moveToFirstEvent: function(elem, eventType, bindType){ - var events = ($._data(elem, 'events') || {})[eventType]; - var fn; - - if(events && events.length > 1){ - fn = events.pop(); - if(!bindType){ - bindType = 'bind'; + + this.options.containerElements.push(this.buttonWrapper[0]); + + if(typeof steps[this.type].start == 'object'){ + steps[this.type].start = this.asNumber(steps[this.type].start); } - if(bindType == 'bind' && events.delegateCount){ - events.splice( events.delegateCount, 0, fn); - } else { - events.unshift( fn ); + + + + for(i = 0; i < createOpts.length; i++){ + this[createOpts[i]](o[createOpts[i]]); } + this.element.data('wsspinner', this); - } - elem = null; - }, - addShadowDom: (function(){ - var resizeTimer; - var lastHeight; - var lastWidth; - - var docObserve = { - init: false, - runs: 0, - test: function(){ - var height = docObserve.getHeight(); - var width = docObserve.getWidth(); - - if(height != docObserve.height || width != docObserve.width){ - docObserve.height = height; - docObserve.width = width; - docObserve.handler({type: 'docresize'}); - docObserve.runs++; - if(docObserve.runs < 9){ - setTimeout(docObserve.test, 90); - } - } else { - docObserve.runs = 0; - } - }, - handler: function(e){ - clearTimeout(resizeTimer); - resizeTimer = setTimeout(function(){ - if(e.type == 'resize'){ - var width = $(window).width(); - var height = $(window).width(); - if(height == lastHeight && width == lastWidth){ - return; - } - lastHeight = height; - lastWidth = width; - - docObserve.height = docObserve.getHeight(); - docObserve.width = docObserve.getWidth(); - - } - $(document).triggerHandler('updateshadowdom'); - }, (e.type == 'resize') ? 50 : 9); - }, - _create: function(){ - $.each({ Height: "getHeight", Width: "getWidth" }, function(name, type){ - var body = document.body; - var doc = document.documentElement; - docObserve[type] = function(){ - return Math.max( - body[ "scroll" + name ], doc[ "scroll" + name ], - body[ "offset" + name ], doc[ "offset" + name ], - doc[ "client" + name ] - ); - }; + this.addBindings(); + + if(!o.min && typeof o.relMin == 'number'){ + o.min = this.asValue(this.getRelNumber(o.relMin)); + $.prop(this.orig, 'min', o.min); + } + + if(!o.max && typeof o.relMax == 'number'){ + o.max = this.asValue(this.getRelNumber(o.relMax)); + $.prop(this.orig, 'max', o.max); + } + + this._init = true; + }, + _addSplitInputs: function(){ + if(!this.inputElements){ + var create = splitInputs[this.type]._create(); + this.splits = create.splits; + this.inputElements = $(create.elements).prependTo(this.element).filter('input'); + } + }, + parseValue: function(){ + var value = this.inputElements.map(function(){ + return $.prop(this, 'value'); + }).get(); + if(!this.options.splitInput){ + value = value[0]; + } + return parseVal[this.type](value, this.options); + }, + formatValue: function(val, noSplit){ + return formatVal[this.type](val, noSplit === false ? false : this.options); + }, + placeholder: function(val){ + var options = this.options; + options.placeholder = val; + var placeholder = val; + if(placeholderFormat[this.type]){ + placeholder = placeholderFormat[this.type](val, this.options); + } + if(options.splitInput && typeof placeholder == 'object'){ + $.each(this.splits, function(i, elem){ + $.prop(elem, 'placeholder', placeholder[i]); }); - }, - start: function(){ - if(!this.init && document.body){ - this.init = true; - this._create(); - this.height = docObserve.getHeight(); - this.width = docObserve.getWidth(); - setInterval(this.test, 600); - $(this.test); - webshims.ready('WINDOWLOAD', this.test); - $(window).bind('resize', this.handler); - (function(){ - var oldAnimate = $.fn.animate; - var animationTimer; - - $.fn.animate = function(){ - clearTimeout(animationTimer); - animationTimer = setTimeout(function(){ - docObserve.test(); - }, 99); - - return oldAnimate.apply(this, arguments); - }; - })(); - } + } else { + this.element.prop('placeholder', placeholder); } - }; - - - webshims.docObserve = function(){ - webshims.ready('DOM', function(){ - docObserve.start(); - }); - }; - return function(nativeElem, shadowElem, opts){ - opts = opts || {}; - if(nativeElem.jquery){ - nativeElem = nativeElem[0]; + }, + getRelNumber: function(rel){ + var start = steps[this.type].start || 0; + if(rel){ + start += rel; } - if(shadowElem.jquery){ - shadowElem = shadowElem[0]; + return start; + }, + addZero: addZero, + _setStartInRange: function(){ + var start = this.getRelNumber(this.options.relDefaultValue); + if(!isNaN(this.minAsNumber) && start < this.minAsNumber){ + start = this.minAsNumber; + } else if(!isNaN(this.maxAsNumber) && start > this.maxAsNumber){ + start = this.maxAsNumber; } - var nativeData = $.data(nativeElem, dataID) || $.data(nativeElem, dataID, {}); - var shadowData = $.data(shadowElem, dataID) || $.data(shadowElem, dataID, {}); - var shadowFocusElementData = {}; - if(!opts.shadowFocusElement){ - opts.shadowFocusElement = shadowElem; - } else if(opts.shadowFocusElement){ - if(opts.shadowFocusElement.jquery){ - opts.shadowFocusElement = opts.shadowFocusElement[0]; - } - shadowFocusElementData = $.data(opts.shadowFocusElement, dataID) || $.data(opts.shadowFocusElement, dataID, shadowFocusElementData); + this.elemHelper.prop('valueAsNumber', start); + this.options.defValue = this.elemHelper.prop('value'); + + }, + reorderInputs: function(){ + if(splitInputs[this.type]){ + var element = this.element; + splitInputs[this.type].sort(element); + setTimeout(function(){ + var data = webshims.data(element); + if(data && data.shadowData){ + data.shadowData.shadowFocusElement = element.find('input')[0] || element[0]; + } + }, 9); } + }, + value: function(val){ + this.valueAsNumber = this.asNumber(val); + this.options.value = val; + if(isNaN(this.valueAsNumber) || (!isNaN(this.minAsNumber) && this.valueAsNumber < this.minAsNumber) || (!isNaN(this.maxAsNumber) && this.valueAsNumber > this.maxAsNumber)){ + this._setStartInRange(); + } else { + this.elemHelper.prop('value', val); + this.options.defValue = ""; + } - nativeData.hasShadow = shadowElem; - shadowFocusElementData.nativeElement = shadowData.nativeElement = nativeElem; - shadowFocusElementData.shadowData = shadowData.shadowData = nativeData.shadowData = { - nativeElement: nativeElem, - shadowElement: shadowElem, - shadowFocusElement: opts.shadowFocusElement - }; - if(opts.shadowChilds){ - opts.shadowChilds.each(function(){ - elementData(this, 'shadowData', shadowData.shadowData); + val = formatVal[this.type](val, this.options); + if(this.options.splitInput){ + + $.each(this.splits, function(i, elem){ + $.prop(elem, 'value', val[i]); }); + } else { + this.element.prop('value', val); } - if(opts.data){ - shadowFocusElementData.shadowData.data = shadowData.shadowData.data = nativeData.shadowData.data = opts.data; - } - opts = null; - webshims.docObserve(); - }; - })(), - propTypes: { - standard: function(descs, name){ - createPropDefault(descs); - if(descs.prop){return;} - descs.prop = { - set: function(val){ - descs.attr.set.call(this, ''+val); - }, - get: function(){ - return descs.attr.get.call(this) || descs.defaultValue; - } + this._propertyChange('value'); + }, + initDataList: function(){ + var listTimer; + var that = this; + var updateList = function(){ + $(that.orig) + .jProp('list') + .off('updateDatalist', updateList) + .on('updateDatalist', updateList) + ; + clearTimeout(listTimer); + listTimer = setTimeout(function(){ + if(that.list){ + that.list(); + } + }, 9); + }; + $(this.orig).onTrigger('listdatalistchange', updateList); }, - "boolean": function(descs, name){ + getOptions: function(){ + var options = {}; + var datalist = $(this.orig).jProp('list'); + datalist.find('option').each(function(){ + options[$.prop(this, 'value')] = $.prop(this, 'label'); + }); + return [options, datalist.data('label')]; + }, + list: function(val){ + if(this.type == 'number' || this.type == 'time'){ + this.element.attr('list', $.attr(this.orig, 'list')); + } + this.options.list = val; + this._propertyChange('list'); + }, + _propertyChange: $.noop, + tabindex: function(val){ + this.options.tabindex = val; + this.inputElements.prop('tabindex', this.options.tabindex); + }, + title: function(val){ + this.options.title = val; + this.element.prop('title', this.options.title); + }, + + min: function(val){ + this.elemHelper.prop('min', val); + this.minAsNumber = this.asNumber(val); + if(this.valueAsNumber != null && isNaN(this.valueAsNumber)){ + this._setStartInRange(); + } + this.options.min = val; + this._propertyChange('min'); + }, + max: function(val){ + this.elemHelper.prop('max', val); + this.maxAsNumber = this.asNumber(val); + if(this.valueAsNumber != null && isNaN(this.valueAsNumber)){ + this._setStartInRange(); + } + this.options.max = val; + this._propertyChange('max'); + }, + step: function(val){ + var defStep = steps[this.type]; + this.options.step = val; + this.elemHelper.prop('step', retDefault(val, defStep.step)); + }, + addBindings: function(){ + var isFocused; - createPropDefault(descs); - if(descs.prop){return;} - descs.prop = { - set: function(val){ - if(val){ - descs.attr.set.call(this, ""); - } else { - descs.removeAttr.value.call(this); + var that = this; + var o = this.options; + + var eventTimer = (function(){ + var events = {}; + return { + init: function(name, curVal, fn){ + if(!events[name]){ + events[name] = {fn: fn}; + $(that.orig).on(name, function(){ + events[name].val = $.prop(that.orig, 'value'); + }); + } + events[name].val = curVal; + }, + call: function(name, val){ + if(events[name] && events[name].val != val){ + clearTimeout(events[name].timer); + events[name].val = val; + events[name].timer = setTimeout(function(){ + events[name].fn(val, that); + }, 9); + } } - }, - get: function(){ - return descs.attr.get.call(this) != null; + }; + })(); + var initChangeEvents = function(){ + eventTimer.init('input', $.prop(that.orig, 'value'), that.options.input); + eventTimer.init('change', $.prop(that.orig, 'value'), that.options.change); + }; + + var step = {}; + + var preventBlur = function(e){ + if(preventBlur.prevent){ + e.preventDefault(); + (isFocused || that.element.getShadowFocusElement()).focus(); + e.stopImmediatePropagation(); + return true; } }; - }, - "src": (function(){ - var anchor = document.createElement('a'); - anchor.style.display = "none"; - return function(descs, name){ + var callSplitChange = (function(){ + var timer; - createPropDefault(descs); - if(descs.prop){return;} - descs.prop = { - set: function(val){ - descs.attr.set.call(this, val); - }, - get: function(){ - var href = this.getAttribute(name); - var ret; - if(href == null){return '';} - - anchor.setAttribute('href', href+'' ); - - if(!$.support.hrefNormalized){ - try { - $(anchor).insertAfter(this); - ret = anchor.getAttribute('href', 4); - } catch(er){ - ret = anchor.getAttribute('href', 4); - } - $(anchor).detach(); + var call = function(e){ + var val; + clearTimeout(timer); + val = that.parseValue(); + $.prop(that.orig, 'value', val); + eventTimer.call('input', val); + if(!e || e.type != 'wsupdatevalue'){ + eventTimer.call('change', val); + } + }; + + var onFocus = function(){ + clearTimeout(timer); + }; + var onBlur = function(e){ + clearTimeout(timer); + timer = setTimeout(call, 0); + + if(e.type == 'change'){ + stopPropagation(e); + if(!o.splitInput){ + call(); } - return ret || anchor.href; } }; + + that.element.on('wsupdatevalue', call); + + that.inputElements + .add(that.buttonWrapper) + .add(that.element) + .on( + { + 'focus focusin': onFocus, + 'blur focusout change': onBlur + } + ) + ; + setTimeout(function(){ + if(that.popover){ + $('> *', that.popover.element) + .on({ + 'focusin': onFocus, + 'focusout': onBlur + }) + ; + } + }, 0); + })(); + + var spinEvents = {}; + var spinElement = o.splitInput ? this.inputElements.filter('.ws-spin') : this.inputElements.eq(0); + var elementEvts = { + blur: function(e){ + if(!preventBlur(e) && !o.disabled && !o.readonly){ + if(!preventBlur.prevent){ + isFocused = false; + } + } + stopPropagation(e); + }, + focus: function(e){ + if(!isFocused){ + initChangeEvents(); + isFocused = this; + } + }, + keypress: function(e){ + if(e.isDefaultPrevented()){return;} + var chr; + var stepped = true; + var code = e.keyCode; + if(!e.ctrlKey && !e.metaKey && curCfg[that.type+'Signs']){ + chr = String.fromCharCode(e.charCode == null ? code : e.charCode); + stepped = !(chr < " " || (curCfg[that.type+'Signs']+'0123456789').indexOf(chr) > -1); + } else { + stepped = false; + } + if(stepped){ + e.preventDefault(); + } + }, + 'input keydown keypress': (function(){ + var timer; + var isStopped = false; + var releaseTab = function(){ + if(isStopped === true){ + isStopped = 'semi'; + timer = setTimeout(releaseTab, 250); + } else { + isStopped = false; + } + }; + var stopTab = function(){ + isStopped = true; + clearTimeout(timer); + timer = setTimeout(releaseTab, 300); + }; + var select = function(){ + this.focus(); + this.select(); + stopTab(); + }; + + return function(e){ + if(o.splitInput && o.jumpInputs){ + if(e.type == 'input'){ + if($.prop(this, 'value').length === $.prop(this, 'maxLength')){ + try { + $(this) + .next() + .next('input') + .each(select) + ; + } catch(er){} + } + } else if(!e.shiftKey && !e.crtlKey && e.keyCode == 9 && (isStopped === true || (isStopped && !$.prop(this, 'value')))){ + e.preventDefault(); + } + } + } + })() }; - })(), - enumarated: function(descs, name){ + var mouseDownInit = function(){ + if(!o.disabled && !isFocused){ + that.element.getShadowFocusElement().focus(); + } + preventBlur.set(); - createPropDefault(descs); - if(descs.prop){return;} - descs.prop = { - set: function(val){ - descs.attr.set.call(this, val); - }, - get: function(){ - var val = (descs.attr.get.call(this) || '').toLowerCase(); - if(!val || descs.limitedTo.indexOf(val) == -1){ - val = descs.defaultValue; + return false; + }; + + preventBlur.set = (function(){ + var timer; + var reset = function(){ + preventBlur.prevent = false; + }; + return function(){ + clearTimeout(timer); + preventBlur.prevent = true; + setTimeout(reset, 9); + }; + })(); + + ['stepUp', 'stepDown'].forEach(function(name){ + step[name] = function(factor){ + if(!o.disabled && !o.readonly){ + if(!isFocused){ + mouseDownInit(); } - return val; + var ret = false; + if (!factor) { + factor = 1; + } + try { + that.elemHelper[name](factor); + ret = that.elemHelper.prop('value'); + that.value(ret); + eventTimer.call('input', ret); + } catch (er) {} + return ret; } }; + }); + + + + this.buttonWrapper.on('mousedown', mouseDownInit); + + this.setInput = function(value){ + that.value(value); + eventTimer.call('input', value); + }; + this.setChange = function(value){ + that.setInput(value); + eventTimer.call('change', value); + }; + + + + this.inputElements.on(elementEvts); + + if(!o.noSpinbtn){ + spinEvents[$.fn.mwheelIntent ? 'mwheelIntent' : 'mousewheel'] = function(e, delta){ + if(delta && isFocused && !o.disabled){ + step[delta > 0 ? 'stepUp' : 'stepDown'](); + e.preventDefault(); + } + }; + spinEvents.keydown = function(e){ + if(o.list || e.isDefaultPrevented() || $.attr(this, 'list')){return;} + var stepped = true; + var code = e.keyCode; + if (code == 38) { + step.stepUp(); + } else if (code == 40) { + step.stepDown(); + } else { + stepped = false; + } + if(stepped){ + e.preventDefault(); + } + }; + + spinElement.attr({'autocomplete': 'off', role: 'spinbutton'}).on(spinEvents); } - -// ,unsignedLong: $.noop -// ,"doubble": $.noop -// ,"long": $.noop -// ,tokenlist: $.noop -// ,settableTokenlist: $.noop - }, - reflectProperties: function(nodeNames, props){ - if(typeof props == 'string'){ - props = props.split(listReg); - } - props.forEach(function(prop){ - webshims.defineNodeNamesProperty(nodeNames, prop, { - prop: { - set: function(val){ - $.attr(this, prop, val); - }, - get: function(){ - return $.attr(this, prop) || ''; + + + if(!o.splitInput){ + $(document).on('wslocalechange',function(){ + if(o.value){ + that.value(o.value); } - } - }); - }); - }, - defineNodeNameProperty: function(nodeName, prop, descs){ - havePolyfill[prop] = true; - - if(descs.reflect){ - webshims.propTypes[descs.propType || 'standard'](descs, prop); + + if(placeholderFormat[that.type] && o.placeholder){ + that.placeholder(o.placeholder); + } + }); + } else { + $(document).onTrigger('wslocalechange',function(){ + that.reorderInputs(); + }); + } + + $('.step-up', this.buttonWrapper) + .on({ + 'mousepressstart mousepressend': mousePress, + 'mousedown mousepress': function(e){ + step.stepUp(); + } + }) + ; + $('.step-down', this.buttonWrapper) + .on({ + 'mousepressstart mousepressend': mousePress, + 'mousedown mousepress': function(e){ + step.stepDown(); + } + }) + ; + initChangeEvents(); } - - ['prop', 'attr', 'removeAttr'].forEach(function(type){ - var desc = descs[type]; - if(desc){ - if(type === 'prop'){ - desc = $.extend({writeable: true}, desc); + }; + + ['readonly', 'disabled'].forEach(function(name){ + spinBtnProto[name] = function(val){ + if(this.options[name] != val || !this._init){ + this.options[name] = !!val; + if(name == 'readonly' && this.options.noInput){ + this.element + .prop(name, true) + .attr({'aria-readonly': this.options[name]}) + ; } else { - desc = $.extend({}, desc, {writeable: true}); + this.element.prop(name, this.options[name]); } - - extendQ[type](nodeName, prop, desc); - if(nodeName != '*' && webshims.cfg.extendNative && type == 'prop' && desc.value && $.isFunction(desc.value)){ - extendNativeValue(nodeName, prop, desc); - } - descs[type] = desc; + this.buttonWrapper[this.options[name] ? 'addClass' : 'removeClass']('ws-'+name); } + }; + }); + + + $.fn.spinbtnUI = function(opts){ + opts = $.extend({ + monthNames: 'monthNames', + size: 1, + startView: 0 + }, opts); + return this.each(function(){ + $.webshims.objectCreate(spinBtnProto, { + element: { + value: $(this) + } + }, opts); }); - if(descs.initAttr){ - initProp.content(nodeName, prop); + }; + })(); + + (function(){ + var picker = {}; + var disable = { + + }; + + var getDateArray = function(date){ + var ret = [date.getFullYear(), addZero(date.getMonth() + 1), addZero(date.getDate())]; + ret.month = ret[0]+'-'+ret[1]; + ret.date = ret[0]+'-'+ret[1]+'-'+ret[2]; + return ret; + }; + var today = getDateArray(new Date()); + + var _setFocus = function(element, _noFocus){ + var setFocus, that; + element = $(element || this.activeButton); + this.activeButton.attr({tabindex: '-1', 'aria-selected': 'false'}); + this.activeButton = element.attr({tabindex: '0', 'aria-selected': 'true'}); + this.index = this.buttons.index(this.activeButton[0]); + + clearTimeout(this.timer); + + if(!this.popover.openedByFocus && !_noFocus){ + that = this; + setFocus = function(noTrigger){ + clearTimeout(that.timer); + that.timer = setTimeout(function(){ + if(element[0]){ + element[0].focus(); + if(noTrigger !== true && !element.is(':focus')){ + setFocus(true); + } + } + }, that.popover.isVisible ? 99 : 360); + }; + this.popover.activateElement(element); + setFocus(); } - return descs; - }, + + }; - defineNodeNameProperties: function(name, descs, propType, _noTmpCache){ - var olddesc; - for(var prop in descs){ - if(!_noTmpCache && descs[prop].initAttr){ - initProp.createTmpCache(name); + var _initialFocus = function(){ + var sel; + if(this.popover.navedInitFocus){ + sel = this.popover.navedInitFocus.sel || this.popover.navedInitFocus; + if((!this.activeButton || !this.activeButton[0]) && this.buttons[sel]){ + this.activeButton = this.buttons[sel](); + } else if(sel){ + this.activeButton = $(sel, this.element); } - if(propType){ - if(descs[prop][propType]){ - //webshims.log('override: '+ name +'['+prop +'] for '+ propType); - } else { - descs[prop][propType] = {}; - ['value', 'set', 'get'].forEach(function(copyProp){ - if(copyProp in descs[prop]){ - descs[prop][propType][copyProp] = descs[prop][copyProp]; - delete descs[prop][copyProp]; - } - }); - } + + if(!this.activeButton[0] && this.popover.navedInitFocus.alt){ + this.activeButton = this.buttons[this.popover.navedInitFocus.alt](); } - descs[prop] = webshims.defineNodeNameProperty(name, prop, descs[prop]); } - if(!_noTmpCache){ - initProp.flushTmpCache(); + + if(!this.activeButton || !this.activeButton[0]){ + this.activeButton = this.buttons.filter('.checked-value'); } - return descs; - }, - - createElement: function(nodeName, create, descs){ - var ret; - if($.isFunction(create)){ - create = { - after: create - }; + + if(!this.activeButton[0]){ + this.activeButton = this.buttons.filter('.this-value'); } - initProp.createTmpCache(nodeName); - if(create.before){ - initProp.createElement(nodeName, create.before); + if(!this.activeButton[0]){ + this.activeButton = this.buttons.eq(0); } - if(descs){ - ret = webshims.defineNodeNameProperties(nodeName, descs, false, true); + + this.setFocus(this.activeButton, this.opts.noFocus); + }; + + + webshims.ListBox = function (element, popover, opts){ + this.element = $('ul', element); + this.popover = popover; + this.opts = opts || {}; + this.buttons = $('button:not(:disabled)', this.element); + + + this.ons(this); + this._initialFocus(); + }; + + webshims.ListBox.prototype = { + setFocus: _setFocus, + _initialFocus: _initialFocus, + prev: function(){ + var index = this.index - 1; + if(index < 0){ + if(this.opts.prev){ + this.popover.navedInitFocus = 'last'; + this.popover.actionFn(this.opts.prev); + this.popover.navedInitFocus = false; + } + } else { + this.setFocus(this.buttons.eq(index)); + } + }, + next: function(){ + var index = this.index + 1; + if(index >= this.buttons.length){ + if(this.opts.next){ + this.popover.navedInitFocus = 'first'; + this.popover.actionFn(this.opts.next); + this.popover.navedInitFocus = false; + } + } else { + this.setFocus(this.buttons.eq(index)); + } + }, + ons: function(that){ + this.element + .on({ + 'keydown': function(e){ + var handled; + var key = e.keyCode; + if(e.ctrlKey){return;} + if(key == 36 || key == 33){ + that.setFocus(that.buttons.eq(0)); + handled = true; + } else if(key == 34 || key == 35){ + that.setFocus(that.buttons.eq(that.buttons.length - 1)); + handled = true; + } else if(key == 38 || key == 37){ + that.prev(); + handled = true; + } else if(key == 40 || key == 39){ + that.next(); + handled = true; + } + if(handled){ + return false; + } + } + }) + ; } - if(create.after){ - initProp.createElement(nodeName, create.after); + }; + + webshims.Grid = function (element, popover, opts){ + this.element = $('tbody', element); + this.popover = popover; + this.opts = opts || {}; + this.buttons = $('button:not(:disabled,.othermonth)', this.element); + + this.ons(this); + + this._initialFocus(); + if(this.popover.openedByFocus){ + this.popover.activeElement = this.activeButton; } - initProp.flushTmpCache(); - return ret; - }, - onNodeNamesPropertyModify: function(nodeNames, props, desc, only){ - if(typeof nodeNames == 'string'){ - nodeNames = nodeNames.split(listReg); + }; + + + + webshims.Grid.prototype = { + setFocus: _setFocus, + _initialFocus: _initialFocus, + + first: function(){ + this.setFocus(this.buttons.eq(0)); + }, + last: function(){ + this.setFocus(this.buttons.eq(this.buttons.length - 1)); + }, + upPage: function(){ + $('.ws-picker-header > button:not(:disabled)', this.popover.element).trigger('click'); + }, + downPage: function(){ + this.activeButton.filter(':not([data-action="changeInput"])').trigger('click'); + }, + ons: function(that){ + this.element + .on({ + 'keydown': function(e){ + var handled; + var key = e.keyCode; + + if(e.shiftKey){return;} + + if((e.ctrlKey && key == 40)){ + handled = 'downPage'; + } else if((e.ctrlKey && key == 38)){ + handled = 'upPage'; + } else if(key == 33 || (e.ctrlKey && key == 37)){ + handled = 'prevPage'; + } else if(key == 34 || (e.ctrlKey && key == 39)){ + handled = 'nextPage'; + } else if(e.keyCode == 36 || e.keyCode == 33){ + handled = 'first'; + } else if(e.keyCode == 35){ + handled = 'last'; + } else if(e.keyCode == 38){ + handled = 'up'; + } else if(e.keyCode == 37){ + handled = 'prev'; + } else if(e.keyCode == 40){ + handled = 'down'; + } else if(e.keyCode == 39){ + handled = 'next'; + } + if(handled){ + that[handled](); + return false; + } + } + }) + ; } - if($.isFunction(desc)){ - desc = {set: desc}; + }; + $.each({ + prevPage: {get: 'last', action: 'prev'}, + nextPage: {get: 'first', action: 'next'} + }, function(name, val){ + webshims.Grid.prototype[name] = function(){ + if(this.opts[val.action]){ + this.popover.navedInitFocus = { + sel: 'button[data-id="'+ this.activeButton.attr('data-id') +'"]:not(:disabled,.othermonth)', + alt: val.get + }; + this.popover.actionFn(this.opts[val.action]); + this.popover.navedInitFocus = false; + } + }; + }); + + $.each({ + up: {traverse: 'prevAll', get: 'last', action: 'prev', reverse: true}, + down: {traverse: 'nextAll', get: 'first', action: 'next'} + }, function(name, val){ + webshims.Grid.prototype[name] = function(){ + var cellIndex = this.activeButton.closest('td').prop('cellIndex'); + var sel = 'td:nth-child('+(cellIndex + 1)+') button:not(:disabled,.othermonth)'; + var button = this.activeButton.closest('tr')[val.traverse](); + + if(val.reverse){ + button = $(button.get().reverse()); + } + button = button.find(sel)[val.get](); + + if(!button[0]){ + if(this.opts[val.action]){ + this.popover.navedInitFocus = sel+':'+val.get; + this.popover.actionFn(this.opts[val.action]); + this.popover.navedInitFocus = false; + } + } else { + this.setFocus(button.eq(0)); + } + }; + }); + + $.each({ + prev: {traverse: 'prevAll',get: 'last', reverse: true}, + next: {traverse: 'nextAll', get: 'first'} + }, function(name, val){ + webshims.Grid.prototype[name] = function(){ + var sel = 'button:not(:disabled,.othermonth)'; + var button = this.activeButton.closest('td')[val.traverse]('td'); + if(val.reverse){ + button = $(button.get().reverse()); + } + button = button.find(sel)[val.get](); + if(!button[0]){ + button = this.activeButton.closest('tr')[val.traverse]('tr'); + if(val.reverse){ + button = $(button.get().reverse()); + } + button = button.find(sel)[val.get](); + } + + if(!button[0]){ + if(this.opts[name]){ + this.popover.navedInitFocus = val.get; + this.popover.actionFn(this.opts[name]); + this.popover.navedInitFocus = false; + } + } else { + this.setFocus(button.eq(0)); + } + }; + }); + + picker.getWeek = function(date){ + var onejan = new Date(date.getFullYear(),0,1); + return Math.ceil((((date - onejan) / 86400000) + onejan.getDay()+1)/7); + }; + picker.getYearList = function(value, data){ + var j, i, val, disabled, lis, prevDisabled, nextDisabled, classStr, classArray, start; + + + var size = data.options.size; + var max = data.options.max.split('-'); + var min = data.options.min.split('-'); + var currentValue = data.options.value.split('-'); + var xthCorrect = 0; + var enabled = 0; + var str = ''; + var rowNum = 0; + + if(data.options.useDecadeBase == 'max' && max[0]){ + xthCorrect = 11 - (max[0] % 12); + } else if(data.options.useDecadeBase == 'min' && min[0]){ + xthCorrect = 11 - (min[0] % 12); } - nodeNames.forEach(function(name){ - if(!modifyProps[name]){ - modifyProps[name] = {}; + value = value[0] * 1; + start = value - ((value + xthCorrect) % (12 * size)); + + + + for(j = 0; j < size; j++){ + if(j){ + start += 12; + } else { + prevDisabled = picker.isInRange([start-1], max, min) ? {'data-action': 'setYearList','value': start-1} : false; } - if(typeof props == 'string'){ - props = props.split(listReg); + + str += '<div class="year-list picker-list ws-index-'+ j +'"><div class="ws-picker-header"><button disabled="disabled">'+ start +' – '+(start + 11)+'</button></div>'; + lis = []; + for(i = 0; i < 12; i++){ + val = start + i ; + classArray = []; + if( !picker.isInRange([val], max, min) ){ + disabled = ' disabled=""'; + } else { + disabled = ''; + enabled++; + } + + if(val == today[0]){ + classArray.push('this-value'); + } + + if(currentValue[0] == val){ + classArray.push('checked-value'); + } + + classStr = classArray.length ? ' class="'+ (classArray.join(' ')) +'"' : ''; + + if(i && !(i % 3)){ + rowNum++; + lis.push('</tr><tr class="ws-row-'+ rowNum +'">'); + } + lis.push('<td class="ws-item-'+ i +'" role="presentation"><button data-id="year-'+ i +'" type="button"'+ disabled + classStr +' data-action="setMonthList" value="'+val+'" tabindex="-1" role="gridcell">'+val+'</button></td>'); } - if(desc.initAttr){ - initProp.createTmpCache(name); + if(j == size - 1){ + nextDisabled = picker.isInRange([val+1], max, min) ? {'data-action': 'setYearList','value': val+1} : false; } - props.forEach(function(prop){ - if(!modifyProps[name][prop]){ - modifyProps[name][prop] = []; - havePolyfill[prop] = true; + str += '<div class="picker-grid"><table role="grid" aria-label="'+ start +' – '+(start + 11)+'"><tbody><tr class="ws-row-0">'+ (lis.join(''))+ '</tr></tbody></table></div></div>'; + } + + return { + enabled: enabled, + main: str, + next: nextDisabled, + prev: prevDisabled, + type: 'Grid' + }; + }; + + + picker.getMonthList = function(value, data){ + + var j, i, name, val, disabled, lis, fullyDisabled, prevDisabled, nextDisabled, classStr, classArray; + var o = data.options; + var size = o.size; + var max = o.max.split('-'); + var min = o.min.split('-'); + var currentValue = o.value.split('-'); + var enabled = 0; + var rowNum = 0; + var str = ''; + + value = value[0] - Math.floor((size - 1) / 2); + for(j = 0; j < size; j++){ + if(j){ + value++; + } else { + prevDisabled = picker.isInRange([value-1], max, min) ? {'data-action': 'setMonthList','value': value-1} : false; + } + if(j == size - 1){ + nextDisabled = picker.isInRange([value+1], max, min) ? {'data-action': 'setMonthList','value': value+1} : false; + } + lis = []; + + if( !picker.isInRange([value, '01'], max, min) && !picker.isInRange([value, '12'], max, min)){ + disabled = ' disabled=""'; + fullyDisabled = true; + } else { + fullyDisabled = false; + disabled = ''; + } + + if(o.minView >= 1){ + disabled = ' disabled=""'; + } + + str += '<div class="month-list picker-list ws-index-'+ j +'"><div class="ws-picker-header">'; + + str += o.selectNav ? + '<select data-action="setMonthList" class="year-select">'+ picker.createYearSelect(value, max, min).join('') +'</select>' : + '<button data-action="setYearList"'+disabled+' value="'+ value +'" tabindex="-1">'+ value +'</button>'; + str += '</div>'; + + for(i = 0; i < 12; i++){ + val = curCfg.date.monthkeys[i+1]; + name = (curCfg.date[o.monthNames] || curCfg.date.monthNames)[i]; + classArray = []; + if(fullyDisabled || !picker.isInRange([value, val], max, min) ){ + disabled = ' disabled=""'; + } else { + disabled = ''; + enabled++; } - if(desc.set){ - if(only){ - desc.set.only = only; - } - modifyProps[name][prop].push(desc.set); + + if(value == today[0] && today[1] == val){ + classArray.push('this-value'); } - if(desc.initAttr){ - initProp.content(name, prop); + if(currentValue[0] == value && currentValue[1] == val){ + classArray.push('checked-value'); } - }); - initProp.flushTmpCache(); + + classStr = (classArray.length) ? ' class="'+ (classArray.join(' ')) +'"' : ''; + if(i && !(i % 3)){ + rowNum++; + lis.push('</tr><tr class="ws-row-'+ rowNum +'">'); + } + + lis.push('<td class="ws-item-'+ i +'" role="presentation"><button data-id="month-'+ i +'" type="button"'+ disabled + classStr +' data-action="'+ (data.type == 'month' ? 'changeInput' : 'setDayList' ) +'" value="'+value+'-'+val+'" tabindex="-1" role="gridcell" aria-label="'+ curCfg.date.monthNames[i] +'">'+name+'</button></td>'); + + } - }); - }, - defineNodeNamesBooleanProperty: function(elementNames, prop, descs){ - if(!descs){ - descs = {}; + str += '<div class="picker-grid"><table role="grid" aria-label="'+value+'"><tbody><tr class="ws-row-0">'+ (lis.join(''))+ '</tr></tbody></table></div></div>'; } - if($.isFunction(descs)){ - descs.set = descs; - } - webshims.defineNodeNamesProperty(elementNames, prop, { - attr: { - set: function(val){ - this.setAttribute(prop, val); - if(descs.set){ - descs.set.call(this, true); + + return { + enabled: enabled, + main: str, + prev: prevDisabled, + next: nextDisabled, + type: 'Grid' + }; + }; + + + picker.getDayList = function(value, data){ + + var j, i, k, day, nDay, name, val, disabled, lis, prevDisabled, nextDisabled, addTr, week, rowNum; + + var lastMotnh, curMonth, otherMonth, dateArray, monthName, fullMonthName, buttonStr, date2, classArray; + var o = data.options; + var size = o.size; + var max = o.max.split('-'); + var min = o.min.split('-'); + var currentValue = o.value.split('-'); + var monthNames = curCfg.date[o.monthNamesHead] || curCfg.date[o.monthNames] || curCfg.date.monthNames; + var enabled = 0; + var str = []; + var date = new Date(value[0], value[1] - 1, 1); + + date.setMonth(date.getMonth() - Math.floor((size - 1) / 2)); + + for(j = 0; j < size; j++){ + date.setDate(1); + lastMotnh = date.getMonth(); + rowNum = 0; + if(!j){ + date2 = new Date(date.getTime()); + date2.setDate(-1); + dateArray = getDateArray(date2); + prevDisabled = picker.isInRange(dateArray, max, min) ? {'data-action': 'setDayList','value': dateArray[0]+'-'+dateArray[1]} : false; + } + + dateArray = getDateArray(date); + + str.push('<div class="day-list picker-list ws-index-'+ j +'"><div class="ws-picker-header">'); + if( o.selectNav ){ + monthName = ['<select data-action="setDayList" class="month-select" tabindex="0">'+ picker.createMonthSelect(dateArray, max, min, monthNames).join('') +'</select>', '<select data-action="setDayList" class="year-select" tabindex="0">'+ picker.createYearSelect(dateArray[0], max, min, '-'+dateArray[1]).join('') +'</select>']; + if(curCfg.date.showMonthAfterYear){ + monthName.reverse(); + } + str.push( monthName.join(' ') ); + } + + fullMonthName = [curCfg.date.monthNames[(dateArray[1] * 1) - 1], dateArray[0]]; + monthName = [monthNames[(dateArray[1] * 1) - 1], dateArray[0]]; + if(curCfg.date.showMonthAfterYear){ + monthName.reverse(); + fullMonthName.reverse(); + } + + if(!data.options.selectNav) { + str.push( + '<button data-action="setMonthList"'+ (o.minView >= 2 ? ' disabled="" ' : '') +' value="'+ dateArray.date +'" tabindex="-1">'+ monthName.join(' ') +'</button>' + ); + } + + + str.push('</div><div class="picker-grid"><table role="grid" aria-label="'+ fullMonthName.join(' ') +'"><thead><tr>'); + + if(data.options.showWeek){ + str.push('<th class="week-header">'+ curCfg.date.weekHeader +'</th>'); + } + for(k = curCfg.date.firstDay; k < curCfg.date.dayNamesShort.length; k++){ + str.push('<th class="day-'+ k +'"><abbr title="'+ curCfg.date.dayNames[k] +'">'+ curCfg.date.dayNamesShort[k] +'</abbr></th>'); + } + k = curCfg.date.firstDay; + while(k--){ + str.push('<th class="day-'+ k +'"><abbr title="'+ curCfg.date.dayNames[k] +'">'+ curCfg.date.dayNamesShort[k] +'</abbr></th>'); + } + str.push('</tr></thead><tbody><tr class="ws-row-0">'); + + if(data.options.showWeek) { + week = picker.getWeek(date); + str.push('<td class="week-cell">'+ week +'</td>'); + } + + for (i = 0; i < 99; i++) { + addTr = (i && !(i % 7)); + curMonth = date.getMonth(); + otherMonth = lastMotnh != curMonth; + day = date.getDay(); + classArray = []; + + if(addTr && otherMonth ){ + str.push('</tr>'); + break; + } + if(addTr){ + rowNum++; + str.push('</tr><tr class="ws-row-'+ rowNum +'">'); + if(data.options.showWeek) { + week++; + str.push('<td class="week-cell">'+ week +'</td>'); } - }, - get: function(){ - var ret = this.getAttribute(prop); - return (ret == null) ? undefined : prop; } - }, - removeAttr: { - value: function(){ - this.removeAttribute(prop); - if(descs.set){ - descs.set.call(this, false); + + if(!i){ + + if(day != curCfg.date.firstDay){ + nDay = day - curCfg.date.firstDay; + if(nDay < 0){ + nDay += 7; + } + date.setDate(date.getDate() - nDay); + day = date.getDay(); + curMonth = date.getMonth(); + otherMonth = lastMotnh != curMonth; } } - }, - reflect: true, - propType: 'boolean', - initAttr: descs.initAttr || false - }); - }, - contentAttr: function(elem, name, val){ - if(!elem.nodeName){return;} - var attr; - if(val === undefined){ - attr = (elem.attributes[name] || {}); - val = attr.specified ? attr.value : null; - return (val == null) ? undefined : val; + + dateArray = getDateArray(date); + buttonStr = '<td role="presentation" class="day-'+ day +'"><button data-id="day-'+ date.getDate() +'" role="gridcell" data-action="changeInput" value="'+ (dateArray.join('-')) +'"'; + + if(otherMonth){ + classArray.push('othermonth'); + } else { + classArray.push('day-'+date.getDate()); + } + + if(dateArray[0] == today[0] && today[1] == dateArray[1] && today[2] == dateArray[2]){ + classArray.push('this-value'); + } + + if(currentValue[0] == dateArray[0] && dateArray[1] == currentValue[1] && dateArray[2] == currentValue[2]){ + classArray.push('checked-value'); + } + + if(classArray.length){ + buttonStr += ' class="'+ classArray.join(' ') +'"'; + } + + if(!picker.isInRange(dateArray, max, min) || (data.options.disableDays && $.inArray(day, data.options.disableDays) != -1)){ + buttonStr += ' disabled=""'; + } + + str.push(buttonStr+' tabindex="-1">'+ date.getDate() +'</button></td>'); + + date.setDate(date.getDate() + 1); + } + str.push('</tbody></table></div></div>'); + if(j == size - 1){ + dateArray = getDateArray(date); + dateArray[2] = 1; + nextDisabled = picker.isInRange(dateArray, max, min) ? {'data-action': 'setDayList','value': dateArray.date} : false; + } } + - if(typeof val == 'boolean'){ - if(!val){ - elem.removeAttribute(name); + return { + enabled: 9, + main: str.join(''), + prev: prevDisabled, + next: nextDisabled, + type: 'Grid' + }; + }; + + picker.isInRange = function(values, max, min){ + var i; + var ret = true; + for(i = 0; i < values.length; i++){ + + if(min[i] && min[i] > values[i]){ + ret = false; + break; + } else if( !(min[i] && min[i] == values[i]) ){ + break; + } + } + if(ret){ + for(i = 0; i < values.length; i++){ + + if((max[i] && max[i] < values[i])){ + ret = false; + break; + } else if( !(max[i] && max[i] == values[i]) ){ + break; + } + } + } + return ret; + }; + + picker.createMonthSelect = function(value, max, min, monthNames){ + if(!monthNames){ + monthNames = curCfg.date.monthNames; + } + + var selected; + var i = 0; + var options = []; + var tempVal = value[1]-1; + for(; i < monthNames.length; i++){ + selected = tempVal == i ? ' selected=""' : ''; + if(selected || picker.isInRange([value[0], i+1], max, min)){ + options.push('<option value="'+ value[0]+'-'+addZero(i+1) + '"'+selected+'>'+ monthNames[i] +'</option>'); + } + } + return options; + }; + + picker.createYearSelect = function(value, max, min, valueAdd){ + + var temp; + var goUp = true; + var goDown = true; + var options = ['<option selected="">'+ value + '</option>']; + var i = 0; + if(!valueAdd){ + valueAdd = ''; + } + while(i < 8 && (goUp || goDown)){ + i++; + temp = value-i; + if(goUp && picker.isInRange([temp], max, min)){ + options.unshift('<option value="'+ (temp+valueAdd) +'">'+ temp +'</option>'); } else { - elem.setAttribute(name, name); + goUp = false; } - } else { - elem.setAttribute(name, val); + temp = value + i; + if(goDown && picker.isInRange([temp], max, min)){ + options.push('<option value="'+ (temp+valueAdd) +'">'+ temp +'</option>'); + } else { + goDown = false; + } } - }, + return options; + }; + + var actions = { + changeInput: function(val, popover, data){ + popover.stopOpen = true; + data.element.getShadowFocusElement().focus(); + setTimeout(function(){ + popover.stopOpen = false; + }, 9); + popover.hide(); + data.setChange(val); + } + }; -// set current Lang: -// - webshims.activeLang(lang:string); -// get current lang -// - webshims.activeLang(); -// get current lang -// webshims.activeLang({ -// register: moduleName:string, -// callback: callback:function -// }); -// get/set including removeLang -// - webshims.activeLang({ -// module: moduleName:string, -// callback: callback:function, -// langObj: languageObj:array/object -// }); - activeLang: (function(){ - var callbacks = []; - var registeredCallbacks = {}; - var currentLang; - var shortLang; - var notLocal = /:\/\/|^\.*\//; - var loadRemoteLang = function(data, lang, options){ - var langSrc; - if(lang && options && $.inArray(lang, options.availabeLangs || []) !== -1){ - data.loading = true; - langSrc = options.langSrc; - if(!notLocal.test(langSrc)){ - langSrc = webshims.cfg.basePath+langSrc; + (function(){ + var retNames = function(name){ + return 'get'+name+'List'; + }; + var retSetNames = function(name){ + return 'set'+name+'List'; + }; + var stops = { + date: 'Day', + week: 'Day', + month: 'Month' + }; + + $.each({'setYearList' : ['Year', 'Month', 'Day'], 'setMonthList': ['Month', 'Day'], 'setDayList': ['Day']}, function(setName, names){ + var getNames = names.map(retNames); + var setNames = names.map(retSetNames); + actions[setName] = function(val, popover, data, startAt){ + val = ''+val; + var o = data.options; + var values = val.split('-'); + if(!startAt){ + startAt = 0; } - webshims.loader.loadScript(langSrc+lang+'.js', function(){ - if(data.langObj[lang]){ - data.loading = false; - callLang(data, true); - } else { - $(function(){ - if(data.langObj[lang]){ - callLang(data, true); + $.each(getNames, function(i, item){ + if(i >= startAt){ + var content = picker[item](values, data); + + if( values.length < 2 || content.enabled > 1 || stops[data.type] === names[i]){ + popover.element + .attr({'data-currentview': setNames[i]}) + .addClass('ws-size-'+o.size) + .data('pickercontent', { + data: data, + content: content, + values: values + }) + ; + popover.bodyElement.html(content.main); + if(content.prev){ + popover.prevElement + .attr(content.prev) + .prop({disabled: false}) + ; + } else { + popover.prevElement + .removeAttr('data-action') + .prop({disabled: true}) + ; } - data.loading = false; - }); + if(content.next){ + popover.nextElement + .attr(content.next) + .prop({disabled: false}) + ; + } else { + popover.nextElement + .removeAttr('data-action') + .prop({disabled: true}) + ; + } + if(webshims[content.type]){ + new webshims[content.type](popover.bodyElement.children(), popover, content); + } + popover.element.trigger('pickerchange'); + return false; + } } }); - return true; + }; + }); + })(); + + picker.commonInit = function(data, popover){ + var actionfn = function(e){ + if(!$(this).is('.othermonth') || $(this).css('cursor') == 'pointer'){ + popover.actionFn({ + 'data-action': $.attr(this, 'data-action'), + value: $(this).val() || $.attr(this, 'value') + }); } return false; }; - var callRegister = function(module){ - if(registeredCallbacks[module]){ - registeredCallbacks[module].forEach(function(data){ - data.callback(); + var id = new Date().getTime(); + var generateList = function(o, max, min){ + var options = []; + var label = ''; + var labelId = ''; + o.options = data.getOptions() || {}; + $('div.ws-options', popover.contentElement).remove(); + $.each(o.options[0], function(val, label){ + var disabled = picker.isInRange(val.split('-'), o.maxS, o.minS) ? + '' : + ' disabled="" ' + ; + options.push('<li role="presentation"><button value="'+ val +'" '+disabled+' data-action="changeInput" tabindex="-1" role="option">'+ (label || data.formatValue(val, false)) +'</button></li>'); + }); + if(options.length){ + id++; + if(o.options[1]){ + labelId = 'datalist-'+id; + label = '<h5 id="'+labelId+'">'+ o.options[1] +'</h5>'; + labelId = ' aria-labelledbyid="'+ labelId +'" '; + } + new webshims.ListBox($('<div class="ws-options">'+label+'<ul role="listbox" '+ labelId +'>'+ options.join('') +'</div>').insertAfter(popover.bodyElement)[0], popover, {noFocus: true}); + } + }; + var updateContent = function(){ + if(popover.isDirty){ + var o = data.options; + o.maxS = o.max.split('-'); + o.minS = o.min.split('-'); + + $('button', popover.buttonRow).each(function(){ + var text; + if($(this).is('.ws-empty')){ + text = curCfg.date.clear; + if(!text){ + text = formcfg[''].date.clear || 'clear'; + webshims.warn("could not get clear text from form cfg"); + } + } else if($(this).is('.ws-current')){ + text = (curCfg[data.type] || {}).currentText; + if(!text){ + text = (formcfg[''][[data.type]] || {}).currentText || 'current'; + webshims.warn("could not get currentText from form cfg"); + } + $.prop(this, 'disabled', !picker.isInRange(today[data.type].split('-'), o.maxS, o.minS)); + } + if(text){ + $(this).text(text).attr({'aria-label': text}); + if(webshims.assumeARIA){ + $.attr(this, 'aria-label', text); + } + } + }); + popover.nextElement.attr({'aria-label': curCfg.date.nextText}); + $('> span', popover.nextElement).html(curCfg.date.nextText); + popover.prevElement.attr({'aria-label': curCfg.date.prevText}); + $('> span', popover.prevElement).html(curCfg.date.prevText); + + generateList(o, o.maxS, o.minS); + } + $('button.ws-empty', popover.buttonRow).prop('disabled', $.prop(data.orig, 'required')); + popover.isDirty = false; }; - var callLang = function(data, _noLoop){ - if(data.activeLang != currentLang && data.activeLang !== shortLang){ - var options = modules[data.module].options; - if( data.langObj[currentLang] || (shortLang && data.langObj[shortLang]) ){ - data.activeLang = currentLang; - data.callback(data.langObj[currentLang] || data.langObj[shortLang], currentLang); - callRegister(data.module); - } else if( !_noLoop && - !loadRemoteLang(data, currentLang, options) && - !loadRemoteLang(data, shortLang, options) && - data.langObj[''] && data.activeLang !== '' ) { - data.activeLang = ''; - data.callback(data.langObj[''], currentLang); - callRegister(data.module); - } + + popover.actionFn = function(obj){ + if(actions[obj['data-action']]){ + actions[obj['data-action']](obj.value, popover, data, 0); + } else { + webshims.warn('no action for '+ obj['data-action']); } }; + popover.contentElement.html('<button class="ws-prev" tabindex="0"><span></span></button> <button class="ws-next" tabindex="0"><span></span></button><div class="ws-picker-body"></div><div class="ws-button-row"><button type="button" class="ws-current" data-action="changeInput" value="'+today[data.type]+'" tabindex="0"></button> <button type="button" data-action="changeInput" value="" class="ws-empty" tabindex="0"></button></div>'); + popover.nextElement = $('button.ws-next', popover.contentElement); + popover.prevElement = $('button.ws-prev', popover.contentElement); + popover.bodyElement = $('div.ws-picker-body', popover.contentElement); + popover.buttonRow = $('div.ws-button-row', popover.contentElement); - var activeLang = function(lang){ - - if(typeof lang == 'string' && lang !== currentLang){ - currentLang = lang; - shortLang = currentLang.split('-')[0]; - if(currentLang == shortLang){ - shortLang = false; - } - $.each(callbacks, function(i, data){ - callLang(data); - }); - } else if(typeof lang == 'object'){ - - if(lang.register){ - if(!registeredCallbacks[lang.register]){ - registeredCallbacks[lang.register] = []; + popover.isDirty = true; + + popover.contentElement + .on('click', 'button[data-action]', actionfn) + .on('change', 'select[data-action]', actionfn) + ; + + popover.contentElement.on({ + keydown: function(e){ + if(e.keyCode == 9){ + var tabbable = $('[tabindex="0"]:not(:disabled)', this).filter(':visible'); + var index = tabbable.index(e.target); + if(e.shiftKey && index <= 0){ + tabbable.last().focus(); + return false; } - registeredCallbacks[lang.register].push(lang); - lang.callback(); - } else { - if(!lang.activeLang){ - lang.activeLang = ''; + if(!e.shiftKey && index >= tabbable.length - 1){ + tabbable.first().focus(); + return false; } - callbacks.push(lang); - callLang(lang); + } else if(e.keyCode == 27){ + data.element.getShadowFocusElement().focus(); + popover.hide(); + return false; } } - return currentLang; - }; + }); - return activeLang; - })() - }); - - $.each({ - defineNodeNamesProperty: 'defineNodeNameProperty', - defineNodeNamesProperties: 'defineNodeNameProperties', - createElements: 'createElement' - }, function(name, baseMethod){ - webshims[name] = function(names, a, b, c){ - if(typeof names == 'string'){ - names = names.split(listReg); - } - var retDesc = {}; - names.forEach(function(nodeName){ - retDesc[nodeName] = webshims[baseMethod](nodeName, a, b, c); + $(data.options.orig).on('input', function(){ + var currentView; + if(data.options.updateOnInput && popover.isVisible && data.options.value && (currentView = popover.element.attr('data-currentview'))){ + actions[currentView]( data.options.value , popover, data, 0); + } }); - return retDesc; - }; - }); - - webshims.isReady('webshimLocalization', true); -}); -//html5a11y -(function($, document){ - //if we support basic styleing or do not support ARIA (assumed) abort - if(!Modernizr.localstorage || ('hidden' in document.createElement('a'))){return;} - - var elemMappings = { - article: "article", - aside: "complementary", - section: "region", - nav: "navigation", - address: "contentinfo" - }; - var addRole = function(elem, role){ - var hasRole = elem.getAttribute('role'); - if (!hasRole) { - elem.setAttribute('role', role); - } - }; - - $.webshims.addReady(function(context, contextElem){ - $.each(elemMappings, function(name, role){ - var elems = $(name, context).add(contextElem.filter(name)); - for (var i = 0, len = elems.length; i < len; i++) { - addRole(elems[i], role); - } - }); - if (context === document) { - var header = document.getElementsByTagName('header')[0]; - var footers = document.getElementsByTagName('footer'); - var footerLen = footers.length; - if (header && !$(header).closest('section, article')[0]) { - addRole(header, 'banner'); - } - if (!footerLen) { - return; - } - var footer = footers[footerLen - 1]; - if (!$(footer).closest('section, article')[0]) { - addRole(footer, 'contentinfo'); - } - } - }); - -})(jQuery, document); - -jQuery.webshims.register('form-datalist', function($, webshims, window, document, undefined){ - "use strict"; - var doc = document; - - /* - * implement propType "element" currently only used for list-attribute (will be moved to dom-extend, if needed) - */ - webshims.propTypes.element = function(descs){ - webshims.createPropDefault(descs, 'attr'); - if(descs.prop){return;} - descs.prop = { - get: function(){ - var elem = descs.attr.get.call(this); - if(elem){ - elem = document.getElementById(elem); - if(elem && descs.propNodeName && !$.nodeName(elem, descs.propNodeName)){ - elem = null; + + data._propertyChange = (function(){ + var timer; + var update = function(){ + if(popover.isVisible){ + updateContent(); } + }; + return function(prop){ + if(prop == 'value'){return;} + popover.isDirty = true; + if(popover.isVisible){ + clearTimeout(timer); + timer = setTimeout(update, 9); + } + }; + })(); + + popover.activeElement = $([]); + + popover.activateElement = function(element){ + element = $(element); + if(element[0] != popover.activeElement[0]){ + popover.activeElement.removeClass('ws-focus'); + element.addClass('ws-focus'); } - return elem || null; - }, - writeable: false + popover.activeElement = element; + }; + popover.element.on({ + wspopoverbeforeshow: function(){ + data.element.triggerHandler('wsupdatevalue'); + updateContent(); + } + }); + + $(document).onTrigger('wslocalechange', data._propertyChange); }; - }; - - - /* - * Implements datalist element and list attribute - */ - - (function(){ - var formsCFG = $.webshims.cfg.forms; - var listSupport = Modernizr.input.list; - 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; - } + picker._common = function(data){ + var popover = webshims.objectCreate(webshims.wsPopover, {}, {prepareFor: data.element}); + var opener = $('<button type="button" class="ws-popover-opener"><span /></button>').appendTo(data.buttonWrapper); + var options = data.options; + var init = false; + + var show = function(){ + if(!options.disabled && !options.readonly && !popover.isVisible){ + if(!init){ + picker.commonInit(data, popover); } - }); - } - - 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(!init || data.options.restartView) { + actions.setYearList( options.defValue || options.value, popover, data, data.options.startView); + } else { + actions[popover.element.attr('data-currentview') || 'setYearList']( options.defValue || options.value, popover, data, 0); } + + init = true; + popover.show(data.element); } }; -// if(formsCFG.customDatalist && (!listSupport || !('selectedOption') in $('<input />')[0])){ -// //currently not supported x-browser (FF4 has not implemented and is not polyfilled ) -// inputListProto.selectedOption = { -// prop: { -// writeable: false, -// get: function(){ -// var elem = this; -// var list = $.prop(elem, 'list'); -// var ret = null; -// var value, options; -// if(!list){return ret;} -// value = $.prop(elem, 'value'); -// if(!value){return ret;} -// options = $.prop(list, 'options'); -// if(!options.length){return ret;} -// $.each(options, function(i, option){ -// if(value == $.prop(option, 'value')){ -// ret = option; -// return false; -// } -// }); -// return ret; -// } -// } -// }; -// } + options.containerElements.push(popover.element[0]); - 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')}); + if(!options.startView){ + options.startView = 0; + } + if(!options.minView){ + options.minView = 0; + } + if(options.startView < options.minView){ + options.minView = options.startView; + webshims.warn("wrong config for minView/startView."); + } + if(!options.size){ + options.size = 1; + } + + popover.element + .addClass(data.type+'-popover input-picker') + .attr({role: 'application'}) + .on({ + wspopoverhide: function(){ + popover.openedByFocus = false; + }, + focusin: function(e){ + if(popover.activateElement){ + popover.openedByFocus = false; + popover.activateElement(e.target); } }, - initAttr: true, - reflect: true, - propType: 'element', - propNodeName: 'datalist' - }; - } else { - //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; - } + focusout: function(){ + if(popover.activeElement){ + popover.activeElement.removeClass('ws-focus'); } - }); - } - inputListProto['list'] = { - attr: { - get: function(){ - var val = webshims.contentAttr(this, 'list'); - if(val != null){ - 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')}); + } + }) + ; + + labelWidth(popover.element.children('div.ws-po-outerbox').attr({role: 'group'}), options.labels, true); + labelWidth(opener, options.labels, true); + + opener + .attr({ + 'tabindex': options.labels.length ? 0 : '-1' + }) + .on({ + mousedown: function(){ + stopPropagation.apply(this, arguments); + popover.preventBlur(); + }, + click: function(){ + if(popover.isVisible && popover.activeElement){ + popover.openedByFocus = false; + popover.activeElement.focus(); } + show(); }, - initAttr: true, - reflect: true, - propType: 'element', - propNodeName: 'datalist' - }; - } - - - webshims.defineNodeNameProperties('input', inputListProto); + focus: function(){ + popover.preventBlur(); + } + }) + ; - if($.event.customEvent){ - $.event.customEvent.updateDatalist = true; - $.event.customEvent.updateInput = true; - $.event.customEvent.datalistselect = true; - } - webshims.addReady(function(context, contextElem){ - contextElem - .filter('datalist > select, datalist, datalist > option, datalist > select > option') - .closest('datalist') - .triggerHandler('updateDatalist') - ; - - }); - - + (function(){ + var mouseFocus = false; + var resetMouseFocus = function(){ + mouseFocus = false; + }; + data.inputElements.on({ + focus: function(){ + if(!popover.stopOpen && (data.options.openOnFocus || (mouseFocus && options.openOnMouseFocus))){ + popover.openedByFocus = !options.noInput; + show(); + } else { + popover.preventBlur(); + } + }, + mousedown: function(){ + mouseFocus = true; + setTimeout(resetMouseFocus, 9); + if(data.element.is(':focus')){ + popover.openedByFocus = !options.noInput; + show(); + } + popover.preventBlur(); + } + }); + })(); + data.popover = popover; }; + picker.month = picker._common; + picker.date = picker.month; - /* - * ShadowList - */ - var listidIndex = 0; + webshims.picker = picker; + })(); + + (function(){ - var noDatalistSupport = { - submit: 1, - button: 1, - reset: 1, - hidden: 1, + var stopCircular, isCheckValidity; + + var modernizrInputTypes = Modernizr.inputtypes; + var inputTypes = { - //ToDo - range: 1, - date: 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 copyProps = [ + 'disabled', + 'readonly', + 'value', + 'min', + 'max', + 'step', + 'title', + 'placeholder' + ]; - var getText = function(elem){ - return (elem.textContent || elem.innerText || $.text([ elem ]) || ''); - }; + // + var copyAttrs = ['data-placeholder', 'tabindex']; + + $.each(copyProps.concat(copyAttrs), function(i, name){ + var fnName = name.replace(/^data\-/, ''); + webshims.onNodeNamesPropertyModify('input', name, function(val){ + if(!stopCircular){ + var shadowData = webshims.data(this, 'shadowData'); + if(shadowData && shadowData.data && shadowData.nativeElement === this && shadowData.data[fnName]){ + shadowData.data[fnName](val); + } + } + }); + }); - var shadowListProto = { - _create: function(opts){ - - if(noDatalistSupport[$.prop(opts.input, 'type')]){return;} - var datalist = opts.datalist; - var data = $.data(opts.input, 'datalistWidget'); - if(datalist && data && data.datalist !== datalist){ - data.datalist = datalist; - data.id = opts.id; + if(options.replaceUI && 'valueAsNumber' in document.createElement('input')){ + var reflectFn = function(val){ + if(webshims.data(this, 'hasShadow')){ + $.prop(this, 'value', $.prop(this, 'value')); + } + }; + + webshims.onNodeNamesPropertyModify('input', 'valueAsNumber', reflectFn); + webshims.onNodeNamesPropertyModify('input', 'valueAsDate', reflectFn); + } + + var extendType = (function(){ + return function(name, data){ + inputTypes[name] = data; + data.attrs = $.merge([], copyAttrs, data.attrs); + data.props = $.merge([], copyProps, data.props); + }; + })(); + + var isVisible = function(){ + return $.css(this, 'display') != 'none'; + }; + var sizeInput = function(data){ + var init; + var updateStyles = function(){ + $.style( data.orig, 'display', '' ); + var hasButtons, marginR, marginL; + var correctWidth = 0.6; + if(!init || data.orig.offsetWidth){ + hasButtons = data.buttonWrapper && data.buttonWrapper.filter(isVisible).length; + marginR = $.css( data.orig, 'marginRight'); + data.element.css({ + marginLeft: $.css( data.orig, 'marginLeft'), + marginRight: hasButtons ? 0 : marginR + }); - data.shadowList.prop('className', 'datalist-polyfill '+ (data.datalist.className || '') + ' '+ data.datalist.id +'-shadowdom'); - if(formsCFG.positionDatalist){ - data.shadowList.insertAfter(opts.input); - } else { - data.shadowList.appendTo('body'); + if(hasButtons){ + marginL = (parseInt(data.buttonWrapper.css('marginLeft'), 10) || 0); + data.element.css({paddingRight: ''}); + + if(marginL < 0){ + marginR = (parseInt(marginR, 10) || 0) + ((data.buttonWrapper.outerWidth() + marginL) * -1); + data.buttonWrapper.css('marginRight', marginR); + data.element + .css({paddingRight: ''}) + .css({ + paddingRight: (parseInt( data.element.css('paddingRight'), 10) || 0) + data.buttonWrapper.outerWidth() + }) + ; + } else { + data.buttonWrapper.css('marginRight', marginR); + correctWidth = data.buttonWrapper.outerWidth(true) + 0.6; + } } - $(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; + + data.element.outerWidth( $(data.orig).outerWidth() - correctWidth ); } - listidIndex++; - var that = this; - this.hideList = $.proxy(that, 'hideList'); - this.timedHide = function(){ - clearTimeout(that.hideTimer); - that.hideTimer = setTimeout(that.hideList, 9); - }; - this.datalist = datalist; - this.id = opts.id; - this.hasViewableData = true; - this._autocomplete = $.attr(opts.input, 'autocomplete'); - $.data(opts.input, 'datalistWidget', this); - this.shadowList = $('<div class="datalist-polyfill '+ (this.datalist.className || '') + ' '+ this.datalist.id +'-shadowdom' +'" />'); + init = true; + $.style( data.orig, 'display', 'none' ); + }; + $(document).onTrigger('updateshadowdom', updateStyles); + }; + + + var implementType = function(){ + var type = $.prop(this, 'type'); + + var i, opts, data, optsName, labels; + if(inputTypes[type] && webshims.implement(this, 'inputwidgets')){ + data = {}; + optsName = type; - if(formsCFG.positionDatalist || $(opts.input).hasClass('position-datalist')){ - this.shadowList.insertAfter(opts.input); - } else { - this.shadowList.appendTo('body'); - } + //todo: do we need deep extend? - this.index = -1; - this.input = opts.input; - this.arrayOptions = []; + labels = $(this).jProp('labels'); - 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).trigger('datalistselect'); - } + opts = $.extend({}, options.widgets, options[type], $($.prop(this, 'form')).data(type) || {}, $(this).data(type) || {}, { + orig: this, + type: type, + labels: labels, + options: {}, + input: function(val){ + opts._change(val, 'input'); + }, + change: function(val){ + opts._change(val, 'change'); + }, + _change: function(val, trigger){ + stopCircular = true; + $.prop(opts.orig, 'value', val); + stopCircular = false; + if(trigger){ + $(opts.orig).trigger(trigger); } - return (e.type != 'mousedown'); - }) - .on('focusout', this.timedHide) - ; + }, + containerElements: [] + }); - 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.isListVisible){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).trigger('datalistselect'); - } - return false; - } - }, - 'focus.datalistWidget': function(){ - if($(this).hasClass('list-focus')){ - that.showList(); - } - }, - 'mousedown.datalistWidget': function(){ - if($(this).is(':focus')){ - that.showList(); - } - }, - 'blur.datalistWidget': this.timedHide - }) - ; - - - $(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 ); - } - } - }); + for(i = 0; i < copyProps.length; i++){ + opts[copyProps[i]] = $.prop(this, copyProps[i]); } - $(window).on('unload.datalist'+this.id+' beforeunload.datalist'+this.id, function(){ - that.destroy(); - }); - }, - destroy: function(){ - 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); - } - }, - _resetListCached: function(e){ - var that = this; - var forceShow; - this.needsUpdate = true; - this.lastUpdatedValue = false; - this.lastUnfoundValue = ''; - - if(!this.updateTimer){ - if(window.QUnit || (forceShow = (e && document.activeElement == that.input))){ - that.updateListOptions(forceShow); - } else { - webshims.ready('WINDOWLOAD', function(){ - that.updateTimer = setTimeout(function(){ - that.updateListOptions(); - that = null; - listidIndex = 1; - }, 200 + (100 * listidIndex)); - }); + + for(i = 0; i < copyAttrs.length; i++){ + optsName = copyAttrs[i].replace(/^data\-/, ''); + if(optsName == 'placeholder' || !opts[optsName]){ + opts[optsName] = $.attr(this, copyAttrs[i]) || opts[optsName]; } } - }, - maskHTML: function(str){ - return str.replace(/</g, '&lt;').replace(/>/g, '&gt;'); - }, - updateListOptions: function(_forceShow){ - this.needsUpdate = false; - clearTimeout(this.updateTimer); - this.updateTimer = false; - this.shadowList - .css({ - fontSize: $.css(this.input, 'fontSize'), - fontFamily: $.css(this.input, 'fontFamily') - }) - ; - this.searchStart = formsCFG.customDatalist && $(this.input).hasClass('search-start'); - var list = []; + data.shim = inputTypes[type]._create(opts); - var values = []; - var allOptions = []; - var rElem, rItem, rOptions, rI, rLen, item; - for(rOptions = $.prop(this.datalist, 'options'), rI = 0, rLen = rOptions.length; rI < rLen; rI++){ - rElem = rOptions[rI]; - if(rElem.disabled){return;} - rItem = { - value: $(rElem).val() || '', - text: $.trim($.attr(rElem, 'label') || getText(rElem)), - className: rElem.className || '', - style: $.attr(rElem, 'style') || '' - }; - if(!rItem.text){ - rItem.text = rItem.value; - } else if(rItem.text != rItem.value){ - rItem.className += ' different-label-value'; - } - values[rI] = rItem.value; - allOptions[rI] = rItem; - } + webshims.addShadowDom(this, data.shim.element, { + data: data.shim || {} + }); - 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')); - } + data.shim.options.containerElements.push(data.shim.element[0]); - this.storedOptions.forEach(function(val, i){ - if(values.indexOf(val) == -1){ - allOptions.push({value: val, text: val, className: 'stored-suggest', style: ''}); + labelWidth($(this).getShadowFocusElement(), labels); + $.attr(this, 'required', $.attr(this, 'required')); + $(this).on('change', function(e){ + if(!stopCircular){ + data.shim.value($.prop(this, 'value')); } }); - for(rI = 0, rLen = allOptions.length; rI < rLen; rI++){ - item = allOptions[rI]; - list[rI] = '<li class="'+ item.className +'" style="'+ item.style +'" tabindex="-1" role="listitem"><span class="option-label">'+ this.maskHTML(item.text) +'</span> <span class="option-value">'+ this.maskHTML(item.value) +'</span></li>'; - } + (function(){ + var has = { + focusin: true, + focus: true + }; + var timer; + var hasFocusTriggered = false; + var hasFocus = false; + + $(data.shim.options.containerElements) + .on({ + 'focusin focus focusout blur': function(e){ + e.stopImmediatePropagation(); + hasFocus = has[e.type]; + clearTimeout(timer); + timer = setTimeout(function(){ + if(hasFocus != hasFocusTriggered){ + hasFocusTriggered = hasFocus; + $(opts.orig).triggerHandler(hasFocus ? 'focus' : 'blur'); + $(opts.orig).trigger(hasFocus ? 'focusin' : 'focusout'); + } + hasFocusTriggered = hasFocus; + }, 0); + } + }) + ; + })(); + - this.arrayOptions = allOptions; - this.shadowList.html('<div class="datalist-outer-box"><div class="datalist-box"><ul role="list">'+ list.join("\n") +'</ul></div></div>'); + data.shim.element.on('change input', stopPropagation); - if($.fn.bgIframe){ - this.shadowList.bgIframe(); + if(Modernizr.formvalidation){ + $(opts.orig).on('firstinvalid', function(e){ + if(!webshims.fromSubmit && isCheckValidity){return;} + $(opts.orig).off('invalid.replacedwidgetbubble').on('invalid.replacedwidgetbubble', function(evt){ + if(!e.isInvalidUIPrevented() && !evt.isDefaultPrevented()){ + webshims.validityAlert.showFor( e.target ); + e.preventDefault(); + evt.preventDefault(); + } + $(opts.orig).off('invalid.replacedwidgetbubble'); + }); + }); } - if(_forceShow || this.isListVisible){ - this.showHideOptions(); - } - }, - showHideOptions: function(_fromShowList){ - var value = $.prop(this.input, 'value').toLowerCase(); - //first check prevent infinite loop, second creates simple lazy optimization - if(value === this.lastUpdatedValue || (this.lastUnfoundValue && value.indexOf(this.lastUnfoundValue) === 0)){ - return; - } - this.lastUpdatedValue = value; - var found = false; - var startSearch = this.searchStart; - var lis = $('li', this.shadowList); - if(value){ - this.arrayOptions.forEach(function(item, i){ - var search; - if(!('lowerText' in item)){ - if(item.text != item.value){ - item.lowerText = item.value.toLowerCase() + item.text.toLowerCase(); - } else { - item.lowerText = item.text.toLowerCase(); - } - } - search = item.lowerText.indexOf(value); - search = startSearch ? !search : search !== -1; - if(search){ - $(lis[i]).removeClass('hidden-item'); - found = true; - } else { - $(lis[i]).addClass('hidden-item'); - } - }); - } else if(lis.length) { - lis.removeClass('hidden-item'); - found = true; + if(data.shim.buttonWrapper && data.shim.buttonWrapper.filter(isVisible).length){ + data.shim.element.addClass('has-input-buttons'); } - this.hasViewableData = found; - if(!_fromShowList && found){ - this.showList(); + if(opts.calculateWidth){ + sizeInput(data.shim); } - if(!found){ - this.lastUnfoundValue = value; - this.hideList(); + $(this).css({display: 'none'}); + } + }; + + if(!modernizrInputTypes.range || options.replaceUI){ + extendType('range', { + _create: function(opts, set){ + return $('<span />').insertAfter(opts.orig).rangeUI(opts).data('rangeUi'); } - }, - setPos: function(){ - this.shadowList.css({marginTop: 0, marginLeft: 0, marginRight: 0, marginBottom: 0}); - var css = (formsCFG.positionDatalist) ? $(this.input).position() : webshims.getRelOffset(this.shadowList, this.input); - css.top += $(this.input).outerHeight(); - css.width = $(this.input).outerWidth() - (parseInt(this.shadowList.css('borderLeftWidth'), 10) || 0) - (parseInt(this.shadowList.css('borderRightWidth'), 10) || 0); - this.shadowList.css({marginTop: '', marginLeft: '', marginRight: '', marginBottom: ''}).css(css); - return css; - }, - showList: function(){ - if(this.isListVisible){return false;} - if(this.needsUpdate){ - this.updateListOptions(); - } - this.showHideOptions(true); - if(!this.hasViewableData){return false;} - this.isListVisible = true; - var that = this; - - that.setPos(); - that.shadowList.addClass('datalist-visible').find('li.active-item').removeClass('active-item'); - - $(window).unbind('.datalist'+that.id); - $(document) - .off('.datalist'+that.id) - .on('mousedown.datalist'+that.id +' focusin.datalist'+that.id, function(e){ - if(e.target === that.input || that.shadowList[0] === e.target || $.contains( that.shadowList[0], e.target )){ - clearTimeout(that.hideTimer); - setTimeout(function(){ - clearTimeout(that.hideTimer); - }, 9); - } else { - that.timedHide(); + }); + } + + if(Modernizr.formvalidation){ + ['input', 'form'].forEach(function(name){ + var desc = webshims.defineNodeNameProperty(name, 'checkValidity', { + prop: { + value: function(){ + isCheckValidity = true; + var ret = desc.prop._supvalue.apply(this, arguments); + isCheckValidity = false; + return ret; } - }) - .on('updateshadowdom.datalist'+that.id, function(){ - that.setPos(); - }) - ; - return true; - }, - hideList: function(){ - if(!this.isListVisible){return false;} - var that = this; - var triggerChange = function(e){ - if(that.changedValue){ - $(that.input).trigger('change'); } - that.changedValue = false; - }; - - that.shadowList.removeClass('datalist-visible list-item-active'); - that.index = -1; - that.isListVisible = false; - if(that.changedValue){ - that.triggeredByDatalist = true; - webshims.triggerInlineForm && webshims.triggerInlineForm(that.input, 'input'); - if($(that.input).is(':focus')){ - $(that.input).one('blur', triggerChange); - } else { - triggerChange(); + }); + }); + } + + + ['number', 'time', 'month', 'date'].forEach(function(name){ + if(!modernizrInputTypes[name] || options.replaceUI){ + extendType(name, { + _create: function(opts, set){ + + if(opts.splitInput && !splitInputs[name]){ + webshims.warn('splitInput not supported for '+ name); + opts.splitInput = false; + } + var markup = opts.splitInput ? + '<span class="ws-'+name+' ws-input" role="group"></span>' : + '<input class="ws-'+name+'" type="text" />'; + var data = $(markup) //role="spinbutton"??? + .insertAfter(opts.orig) + .spinbtnUI(opts) + .data('wsspinner') + ; + if(webshims.picker && webshims.picker[name]){ + webshims.picker[name](data); + } + data.buttonWrapper.addClass('input-button-size-'+(data.buttonWrapper.children().filter(isVisible).length)); + return data; } - that.triggeredByDatalist = false; - } - $(document).unbind('.datalist'+that.id); - $(window) - .off('.datalist'+that.id) - .one('resize.datalist'+that.id, function(){ - that.shadowList.css({top: 0, left: 0}); - }) - ; - 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 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; - } - }, - 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; + }); } - }; + }); - //init datalist update - initializeDatalist(); + + webshims.addReady(function(context, contextElem){ + $('input', context) + .add(contextElem.filter('input')) + .each(implementType) + ; + }); })(); - -}); \ No newline at end of file +}); +