webshims-rails 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/lib/webshims-rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/webshims/extras/custom-validity.js +253 -253
  3. data/vendor/assets/javascripts/webshims/extras/modernizr-custom.js +534 -534
  4. data/vendor/assets/javascripts/webshims/extras/mousepress.js +60 -60
  5. data/vendor/assets/javascripts/webshims/minified/polyfiller.js +1 -1
  6. data/vendor/assets/javascripts/webshims/minified/shims/combos/10.js +1 -1
  7. data/vendor/assets/javascripts/webshims/minified/shims/combos/12.js +1 -1
  8. data/vendor/assets/javascripts/webshims/minified/shims/combos/16.js +1 -1
  9. data/vendor/assets/javascripts/webshims/minified/shims/combos/17.js +1 -1
  10. data/vendor/assets/javascripts/webshims/minified/shims/combos/19.js +1 -1
  11. data/vendor/assets/javascripts/webshims/minified/shims/combos/2.js +1 -1
  12. data/vendor/assets/javascripts/webshims/minified/shims/combos/20.js +1 -1
  13. data/vendor/assets/javascripts/webshims/minified/shims/combos/21.js +1 -1
  14. data/vendor/assets/javascripts/webshims/minified/shims/combos/22.js +1 -1
  15. data/vendor/assets/javascripts/webshims/minified/shims/combos/23.js +1 -1
  16. data/vendor/assets/javascripts/webshims/minified/shims/combos/24.js +1 -1
  17. data/vendor/assets/javascripts/webshims/minified/shims/combos/25.js +1 -1
  18. data/vendor/assets/javascripts/webshims/minified/shims/combos/26.js +1 -1
  19. data/vendor/assets/javascripts/webshims/minified/shims/combos/27.js +1 -1
  20. data/vendor/assets/javascripts/webshims/minified/shims/combos/3.js +1 -1
  21. data/vendor/assets/javascripts/webshims/minified/shims/combos/4.js +1 -1
  22. data/vendor/assets/javascripts/webshims/minified/shims/combos/5.js +1 -1
  23. data/vendor/assets/javascripts/webshims/minified/shims/combos/59.js +1 -1
  24. data/vendor/assets/javascripts/webshims/minified/shims/combos/8.js +1 -1
  25. data/vendor/assets/javascripts/webshims/minified/shims/combos/9.js +1 -1
  26. data/vendor/assets/javascripts/webshims/minified/shims/form-core.js +1 -1
  27. data/vendor/assets/javascripts/webshims/minified/shims/form-message.js +1 -1
  28. data/vendor/assets/javascripts/webshims/minified/shims/i18n/errormessages-de.txt +33 -33
  29. data/vendor/assets/javascripts/webshims/minified/shims/i18n/errormessages-en.txt +34 -34
  30. data/vendor/assets/javascripts/webshims/minified/shims/mediaelement-core.js +1 -1
  31. data/vendor/assets/javascripts/webshims/minified/shims/mediaelement-jaris.js +1 -1
  32. data/vendor/assets/javascripts/webshims/minified/shims/mediaelement-swf.js +1 -1
  33. data/vendor/assets/javascripts/webshims/minified/shims/swf/JarisFLVPlayer.swf +0 -0
  34. data/vendor/assets/javascripts/webshims/polyfiller.js +1188 -1188
  35. data/vendor/assets/javascripts/webshims/shims/FlashCanvasPro/README +82 -82
  36. data/vendor/assets/javascripts/webshims/shims/combos/1.js +1752 -1752
  37. data/vendor/assets/javascripts/webshims/shims/combos/10.js +3310 -3311
  38. data/vendor/assets/javascripts/webshims/shims/combos/11.js +1631 -1631
  39. data/vendor/assets/javascripts/webshims/shims/combos/12.js +1695 -1696
  40. data/vendor/assets/javascripts/webshims/shims/combos/13.js +1098 -1098
  41. data/vendor/assets/javascripts/webshims/shims/combos/14.js +477 -477
  42. data/vendor/assets/javascripts/webshims/shims/combos/15.js +317 -317
  43. data/vendor/assets/javascripts/webshims/shims/combos/16.js +2177 -2154
  44. data/vendor/assets/javascripts/webshims/shims/combos/17.js +2354 -2319
  45. data/vendor/assets/javascripts/webshims/shims/combos/18.js +1322 -1322
  46. data/vendor/assets/javascripts/webshims/shims/combos/19.js +2262 -2238
  47. data/vendor/assets/javascripts/webshims/shims/combos/2.js +2376 -2340
  48. data/vendor/assets/javascripts/webshims/shims/combos/20.js +1557 -1558
  49. data/vendor/assets/javascripts/webshims/shims/combos/21.js +1745 -1733
  50. data/vendor/assets/javascripts/webshims/shims/combos/22.js +2360 -2361
  51. data/vendor/assets/javascripts/webshims/shims/combos/23.js +2342 -2331
  52. data/vendor/assets/javascripts/webshims/shims/combos/24.js +2859 -2836
  53. data/vendor/assets/javascripts/webshims/shims/combos/25.js +1547 -1548
  54. data/vendor/assets/javascripts/webshims/shims/combos/26.js +2178 -2155
  55. data/vendor/assets/javascripts/webshims/shims/combos/27.js +3311 -3312
  56. data/vendor/assets/javascripts/webshims/shims/combos/3.js +3058 -3022
  57. data/vendor/assets/javascripts/webshims/shims/combos/4.js +807 -771
  58. data/vendor/assets/javascripts/webshims/shims/combos/5.js +1063 -1027
  59. data/vendor/assets/javascripts/webshims/shims/combos/59.js +1745 -1709
  60. data/vendor/assets/javascripts/webshims/shims/combos/6.js +384 -384
  61. data/vendor/assets/javascripts/webshims/shims/combos/7.js +640 -640
  62. data/vendor/assets/javascripts/webshims/shims/combos/8.js +1546 -1547
  63. data/vendor/assets/javascripts/webshims/shims/combos/9.js +2507 -2508
  64. data/vendor/assets/javascripts/webshims/shims/details.js +148 -148
  65. data/vendor/assets/javascripts/webshims/shims/dom-extend.js +949 -949
  66. data/vendor/assets/javascripts/webshims/shims/es5.js +802 -802
  67. data/vendor/assets/javascripts/webshims/shims/excanvas.js +924 -924
  68. data/vendor/assets/javascripts/webshims/shims/form-core.js +630 -606
  69. data/vendor/assets/javascripts/webshims/shims/form-datalist.js +681 -681
  70. data/vendor/assets/javascripts/webshims/shims/form-message.js +176 -164
  71. data/vendor/assets/javascripts/webshims/shims/form-native-extend.js +255 -255
  72. data/vendor/assets/javascripts/webshims/shims/form-number-date-api.js +383 -383
  73. data/vendor/assets/javascripts/webshims/shims/form-shim-extend.js +1568 -1568
  74. data/vendor/assets/javascripts/webshims/shims/geolocation.js +168 -168
  75. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-ar.js +32 -32
  76. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-ch-ZN.js +32 -32
  77. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-de.txt +33 -33
  78. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-el.js +32 -32
  79. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-en.txt +34 -34
  80. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-es.js +31 -31
  81. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-fr.js +32 -32
  82. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-he.js +32 -32
  83. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-hi.js +32 -32
  84. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-hu.js +32 -32
  85. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-it.js +32 -32
  86. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-ja.js +32 -32
  87. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-nl.js +32 -32
  88. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-pt-PT.js +32 -32
  89. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-ru.js +31 -31
  90. data/vendor/assets/javascripts/webshims/shims/i18n/errormessages-sv.js +32 -32
  91. data/vendor/assets/javascripts/webshims/shims/json-storage.js +308 -308
  92. data/vendor/assets/javascripts/webshims/shims/mediaelement-core.js +596 -597
  93. data/vendor/assets/javascripts/webshims/shims/mediaelement-jaris.js +891 -891
  94. data/vendor/assets/javascripts/webshims/shims/mediaelement-native-fix.js +98 -98
  95. data/vendor/assets/javascripts/webshims/shims/mediaelement-swf.js +960 -960
  96. data/vendor/assets/javascripts/webshims/shims/mediaelement-yt.js +543 -543
  97. data/vendor/assets/javascripts/webshims/shims/styles/shim.css +697 -697
  98. data/vendor/assets/javascripts/webshims/shims/swf/JarisFLVPlayer.swf +0 -0
  99. metadata +2 -4
  100. data/vendor/assets/javascripts/webshims/minified/shims/range-ui.js +0 -1
  101. data/vendor/assets/javascripts/webshims/shims/range-ui.js +0 -66
@@ -1,1710 +1,1746 @@
1
- //additional tests for partial implementation of forms features
2
- (function($){
3
- "use strict";
4
- var Modernizr = window.Modernizr;
5
- var webshims = $.webshims;
6
- var bugs = webshims.bugs;
7
- var form = $('<form action="#" style="width: 1px; height: 1px; overflow: hidden;"><select name="b" required="" /><input required="" name="a" /></form>');
8
- var testRequiredFind = function(){
9
- if(form[0].querySelector){
10
- try {
11
- bugs.findRequired = !(form[0].querySelector('select:required'));
12
- } catch(er){
13
- bugs.findRequired = false;
14
- }
15
- }
16
- };
17
- var inputElem = $('input', form).eq(0);
18
- var onDomextend = function(fn){
19
- webshims.loader.loadList(['dom-extend']);
20
- webshims.ready('dom-extend', fn);
21
- };
22
-
23
- bugs.findRequired = false;
24
- bugs.validationMessage = false;
25
-
26
- webshims.capturingEventPrevented = function(e){
27
- if(!e._isPolyfilled){
28
- var isDefaultPrevented = e.isDefaultPrevented;
29
- var preventDefault = e.preventDefault;
30
- e.preventDefault = function(){
31
- clearTimeout($.data(e.target, e.type + 'DefaultPrevented'));
32
- $.data(e.target, e.type + 'DefaultPrevented', setTimeout(function(){
33
- $.removeData(e.target, e.type + 'DefaultPrevented');
34
- }, 30));
35
- return preventDefault.apply(this, arguments);
36
- };
37
- e.isDefaultPrevented = function(){
38
- return !!(isDefaultPrevented.apply(this, arguments) || $.data(e.target, e.type + 'DefaultPrevented') || false);
39
- };
40
- e._isPolyfilled = true;
41
- }
42
- };
43
-
44
- if(!Modernizr.formvalidation || bugs.bustedValidity){
45
- testRequiredFind();
46
- return;
47
- }
48
-
49
- //create delegatable events
50
- webshims.capturingEvents(['input']);
51
- webshims.capturingEvents(['invalid'], true);
52
-
53
- if(window.opera || window.testGoodWithFix){
54
-
55
- form.appendTo('head');
56
-
57
- testRequiredFind();
58
- bugs.validationMessage = !(inputElem.prop('validationMessage'));
59
-
60
- webshims.reTest(['form-native-extend', 'form-message']);
61
-
62
- form.remove();
63
-
64
- $(function(){
65
- onDomextend(function(){
66
-
67
- //Opera shows native validation bubbles in case of input.checkValidity()
68
- // Opera 11.6/12 hasn't fixed this issue right, it's buggy
69
- var preventDefault = function(e){
70
- e.preventDefault();
71
- };
72
-
73
- ['form', 'input', 'textarea', 'select'].forEach(function(name){
74
- var desc = webshims.defineNodeNameProperty(name, 'checkValidity', {
75
- prop: {
76
- value: function(){
77
- if (!webshims.fromSubmit) {
78
- $(this).on('invalid.checkvalidity', preventDefault);
79
- }
80
-
81
- webshims.fromCheckValidity = true;
82
- var ret = desc.prop._supvalue.apply(this, arguments);
83
- if (!webshims.fromSubmit) {
84
- $(this).unbind('invalid.checkvalidity', preventDefault);
85
- }
86
- webshims.fromCheckValidity = false;
87
- return ret;
88
- }
89
- }
90
- });
91
- });
92
-
93
- });
94
- });
95
- }
96
-
97
- if($.browser.webkit && !webshims.bugs.bustedValidity){
98
- (function(){
99
- var elems = /^(?:textarea|input)$/i;
100
- var form = false;
101
-
102
- document.addEventListener('contextmenu', function(e){
103
- if(elems.test( e.target.nodeName || '') && (form = e.target.form)){
104
- setTimeout(function(){
105
- form = false;
106
- }, 1);
107
- }
108
- }, false);
109
-
110
- $(window).on('invalid', function(e){
111
- if(e.originalEvent && form && form == e.target.form){
112
- e.wrongWebkitInvalid = true;
113
- e.stopImmediatePropagation();
114
- }
115
- });
116
- })();
117
- }
118
- })(jQuery);
119
-
120
- jQuery.webshims.register('form-core', function($, webshims, window, document, undefined, options){
121
- "use strict";
122
-
123
- var groupTypes = {radio: 1};
124
- var checkTypes = {checkbox: 1, radio: 1};
125
- var emptyJ = $([]);
126
- var bugs = webshims.bugs;
127
- var getGroupElements = function(elem){
128
- elem = $(elem);
129
- var name;
130
- var form;
131
- var ret = emptyJ;
132
- if(groupTypes[elem[0].type]){
133
- form = elem.prop('form');
134
- name = elem[0].name;
135
- if(!name){
136
- ret = elem;
137
- } else if(form){
138
- ret = $(form[name]);
139
- } else {
140
- ret = $(document.getElementsByName(name)).filter(function(){
141
- return !$.prop(this, 'form');
142
- });
143
- }
144
- ret = ret.filter('[type="radio"]');
145
- }
146
- return ret;
147
- };
148
-
149
- var getContentValidationMessage = webshims.getContentValidationMessage = function(elem, validity, key){
150
- var message = $(elem).data('errormessage') || elem.getAttribute('x-moz-errormessage') || '';
151
- if(key && message[key]){
152
- message = message[key];
153
- }
154
- if(typeof message == 'object'){
155
- validity = validity || $.prop(elem, 'validity') || {valid: 1};
156
- if(!validity.valid){
157
- $.each(validity, function(name, prop){
158
- if(prop && name != 'valid' && message[name]){
159
- message = message[name];
160
- return false;
161
- }
162
- });
163
- }
164
- }
165
-
166
- if(typeof message == 'object'){
167
- message = message.defaultMessage;
168
- }
169
- return message || '';
170
- };
171
-
172
- /*
173
- * Selectors for all browsers
174
- */
175
- var rangeTypes = {number: 1, range: 1, date: 1/*, time: 1, 'datetime-local': 1, datetime: 1, month: 1, week: 1*/};
176
- var hasInvalid = function(elem){
177
- var ret = false;
178
- $($.prop(elem, 'elements')).each(function(){
179
- ret = $(this).is(':invalid');
180
- if(ret){
181
- return false;
182
- }
183
- });
184
- return ret;
185
- };
186
- $.extend($.expr[":"], {
187
- "valid-element": function(elem){
188
- return $.nodeName(elem, 'form') ? !hasInvalid(elem) :!!($.prop(elem, 'willValidate') && isValid(elem));
189
- },
190
- "invalid-element": function(elem){
191
- return $.nodeName(elem, 'form') ? hasInvalid(elem) : !!($.prop(elem, 'willValidate') && !isValid(elem));
192
- },
193
- "required-element": function(elem){
194
- return !!($.prop(elem, 'willValidate') && $.prop(elem, 'required'));
195
- },
196
- "user-error": function(elem){
197
- return ($.prop(elem, 'willValidate') && $(elem).hasClass('user-error'));
198
- },
199
- "optional-element": function(elem){
200
- return !!($.prop(elem, 'willValidate') && $.prop(elem, 'required') === false);
201
- },
202
- "in-range": function(elem){
203
- if(!rangeTypes[$.prop(elem, 'type')] || !$.prop(elem, 'willValidate')){
204
- return false;
205
- }
206
- var val = $.prop(elem, 'validity');
207
- return !!(val && !val.rangeOverflow && !val.rangeUnderflow);
208
- },
209
- "out-of-range": function(elem){
210
- if(!rangeTypes[$.prop(elem, 'type')] || !$.prop(elem, 'willValidate')){
211
- return false;
212
- }
213
- var val = $.prop(elem, 'validity');
214
- return !!(val && (val.rangeOverflow || val.rangeUnderflow));
215
- }
216
-
217
- });
218
-
219
- ['valid', 'invalid', 'required', 'optional'].forEach(function(name){
220
- $.expr[":"][name] = $.expr.filters[name+"-element"];
221
- });
222
-
223
-
224
- $.expr[":"].focus = function( elem ) {
225
- try {
226
- var doc = elem.ownerDocument;
227
- return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus());
228
- } catch(e){}
229
- return false;
230
- };
231
-
232
- var customEvents = $.event.customEvent || {};
233
- var isValid = function(elem){
234
- return ($.prop(elem, 'validity') || {valid: 1}).valid;
235
- };
236
-
237
- if (bugs.bustedValidity || bugs.findRequired) {
238
- (function(){
239
- var find = $.find;
240
- var matchesSelector = $.find.matchesSelector;
241
-
242
- var regExp = /(\:valid|\:invalid|\:optional|\:required|\:in-range|\:out-of-range)(?=[\s\[\~\.\+\>\:\#*]|$)/ig;
243
- var regFn = function(sel){
244
- return sel + '-element';
245
- };
246
-
247
- $.find = (function(){
248
- var slice = Array.prototype.slice;
249
- var fn = function(sel){
250
- var ar = arguments;
251
- ar = slice.call(ar, 1, ar.length);
252
- ar.unshift(sel.replace(regExp, regFn));
253
- return find.apply(this, ar);
254
- };
255
- for (var i in find) {
256
- if(find.hasOwnProperty(i)){
257
- fn[i] = find[i];
258
- }
259
- }
260
- return fn;
261
- })();
262
- if(!Modernizr.prefixed || Modernizr.prefixed("matchesSelector", document.documentElement)){
263
- $.find.matchesSelector = function(node, expr){
264
- expr = expr.replace(regExp, regFn);
265
- return matchesSelector.call(this, node, expr);
266
- };
267
- }
268
-
269
- })();
270
- }
271
-
272
- //ToDo needs testing
273
- var oldAttr = $.prop;
274
- var changeVals = {selectedIndex: 1, value: 1, checked: 1, disabled: 1, readonly: 1};
275
- $.prop = function(elem, name, val){
276
- var ret = oldAttr.apply(this, arguments);
277
- if(elem && 'form' in elem && changeVals[name] && val !== undefined && $(elem).hasClass(invalidClass)){
278
- if(isValid(elem)){
279
- $(elem).getShadowElement().removeClass(invalidClasses);
280
- if(name == 'checked' && val) {
281
- getGroupElements(elem).not(elem).removeClass(invalidClasses).removeAttr('aria-invalid');
282
- }
283
- }
284
- }
285
- return ret;
286
- };
287
-
288
- var returnValidityCause = function(validity, elem){
289
- var ret;
290
- $.each(validity, function(name, value){
291
- if(value){
292
- ret = (name == 'customError') ? $.prop(elem, 'validationMessage') : name;
293
- return false;
294
- }
295
- });
296
- return ret;
297
- };
298
-
299
- var isInGroup = function(name){
300
- var ret;
301
- try {
302
- ret = document.activeElement.name === name;
303
- } catch(e){}
304
- return ret;
305
- };
306
- /* form-ui-invalid/form-ui-valid are deprecated. use user-error/user-succes instead */
307
- var invalidClass = 'user-error';
308
- var invalidClasses = 'user-error form-ui-invalid';
309
- var validClass = 'user-success';
310
- var validClasses = 'user-success form-ui-valid';
311
- var switchValidityClass = function(e){
312
- var elem, timer;
313
- if(!e.target){return;}
314
- elem = $(e.target).getNativeElement()[0];
315
- if(elem.type == 'submit' || !$.prop(elem, 'willValidate')){return;}
316
- timer = $.data(elem, 'webshimsswitchvalidityclass');
317
- var switchClass = function(){
318
- if(e.type == 'focusout' && elem.type == 'radio' && isInGroup(elem.name)){return;}
319
- var validity = $.prop(elem, 'validity');
320
- var shadowElem = $(elem).getShadowElement();
321
- var addClass, removeClass, trigger, generaltrigger, validityCause;
322
-
323
- $(elem).trigger('refreshCustomValidityRules');
324
- if(validity.valid){
325
- if(!shadowElem.hasClass(validClass)){
326
- addClass = validClasses;
327
- removeClass = invalidClasses;
328
- generaltrigger = 'changedvaliditystate';
329
- trigger = 'changedvalid';
330
- if(checkTypes[elem.type] && elem.checked){
331
- getGroupElements(elem).not(elem).removeClass(removeClass).addClass(addClass).removeAttr('aria-invalid');
332
- }
333
- $.removeData(elem, 'webshimsinvalidcause');
334
- }
335
- } else {
336
- validityCause = returnValidityCause(validity, elem);
337
- if($.data(elem, 'webshimsinvalidcause') != validityCause){
338
- $.data(elem, 'webshimsinvalidcause', validityCause);
339
- generaltrigger = 'changedvaliditystate';
340
- }
341
- if(!shadowElem.hasClass(invalidClass)){
342
- addClass = invalidClasses;
343
- removeClass = validClasses;
344
- if (checkTypes[elem.type] && !elem.checked) {
345
- getGroupElements(elem).not(elem).removeClass(removeClass).addClass(addClass);
346
- }
347
- trigger = 'changedinvalid';
348
- }
349
- }
350
- if(addClass){
351
- shadowElem.addClass(addClass).removeClass(removeClass);
352
- //jQuery 1.6.1 IE9 bug (doubble trigger bug)
353
- setTimeout(function(){
354
- $(elem).trigger(trigger);
355
- }, 0);
356
- }
357
- if(generaltrigger){
358
- setTimeout(function(){
359
- $(elem).trigger(generaltrigger);
360
- }, 0);
361
- }
362
- $.removeData(e.target, 'webshimsswitchvalidityclass');
363
- };
364
-
365
- if(timer){
366
- clearTimeout(timer);
367
- }
368
- if(e.type == 'refreshvalidityui'){
369
- switchClass();
370
- } else {
371
- $.data(elem, 'webshimsswitchvalidityclass', setTimeout(switchClass, 9));
372
- }
373
- };
374
-
375
- $(document).on(options.validityUIEvents || 'focusout change refreshvalidityui', switchValidityClass);
376
- customEvents.changedvaliditystate = true;
377
- customEvents.refreshCustomValidityRules = true;
378
- customEvents.changedvalid = true;
379
- customEvents.changedinvalid = true;
380
- customEvents.refreshvalidityui = true;
381
-
382
-
383
- webshims.triggerInlineForm = function(elem, event){
384
- $(elem).trigger(event);
385
- };
386
-
387
- webshims.modules["form-core"].getGroupElements = getGroupElements;
388
-
389
-
390
- var setRoot = function(){
391
- webshims.scrollRoot = ($.browser.webkit || document.compatMode == 'BackCompat') ?
392
- $(document.body) :
393
- $(document.documentElement)
394
- ;
395
- };
396
- setRoot();
397
- webshims.ready('DOM', setRoot);
398
-
399
- webshims.getRelOffset = function(posElem, relElem){
400
- posElem = $(posElem);
401
- var offset = $(relElem).offset();
402
- var bodyOffset;
403
- $.swap($(posElem)[0], {visibility: 'hidden', display: 'inline-block', left: 0, top: 0}, function(){
404
- bodyOffset = posElem.offset();
405
- });
406
- offset.top -= bodyOffset.top;
407
- offset.left -= bodyOffset.left;
408
- return offset;
409
- };
410
-
411
- /* some extra validation UI */
412
- webshims.validityAlert = (function(){
413
- var alertElem = (!$.browser.msie || parseInt($.browser.version, 10) > 7) ? 'span' : 'label';
414
- var errorBubble;
415
- var hideTimer = false;
416
- var focusTimer = false;
417
- var resizeTimer = false;
418
- var boundHide;
419
-
420
- var api = {
421
- hideDelay: 5000,
422
-
423
- showFor: function(elem, message, noFocusElem, noBubble){
424
- api._create();
425
- elem = $(elem);
426
- var visual = $(elem).getShadowElement();
427
- var offset = api.getOffsetFromBody(visual);
428
- api.clear();
429
- if(noBubble){
430
- this.hide();
431
- } else {
432
- this.getMessage(elem, message);
433
- this.position(visual, offset);
434
-
435
- this.show();
436
- if(this.hideDelay){
437
- hideTimer = setTimeout(boundHide, this.hideDelay);
438
- }
439
- $(window)
440
- .on('resize.validityalert', function(){
441
- clearTimeout(resizeTimer);
442
- resizeTimer = setTimeout(function(){
443
- api.position(visual);
444
- }, 9);
445
- })
446
- ;
447
- }
448
-
449
- if(!noFocusElem){
450
- this.setFocus(visual, offset);
451
- }
452
- },
453
- getOffsetFromBody: function(elem){
454
- return webshims.getRelOffset(errorBubble, elem);
455
- },
456
- setFocus: function(visual, offset){
457
- var focusElem = $(visual).getShadowFocusElement();
458
- var scrollTop = webshims.scrollRoot.scrollTop();
459
- var elemTop = ((offset || focusElem.offset()).top) - 30;
460
- var smooth;
461
-
462
- if(webshims.getID && alertElem == 'label'){
463
- errorBubble.attr('for', webshims.getID(focusElem));
464
- }
465
-
466
- if(scrollTop > elemTop){
467
- webshims.scrollRoot.animate(
468
- {scrollTop: elemTop - 5},
469
- {
470
- queue: false,
471
- duration: Math.max( Math.min( 600, (scrollTop - elemTop) * 1.5 ), 80 )
472
- }
473
- );
474
- smooth = true;
475
- }
476
- try {
477
- focusElem[0].focus();
478
- } catch(e){}
479
- if(smooth){
480
- webshims.scrollRoot.scrollTop(scrollTop);
481
- setTimeout(function(){
482
- webshims.scrollRoot.scrollTop(scrollTop);
483
- }, 0);
484
- }
485
- setTimeout(function(){
486
- $(document).on('focusout.validityalert', boundHide);
487
- }, 10);
488
- },
489
- getMessage: function(elem, message){
490
- if (!message) {
491
- message = getContentValidationMessage(elem[0]) || elem.prop('validationMessage');
492
- }
493
- if (message) {
494
- $('span.va-box', errorBubble).text(message);
495
- }
496
- else {
497
- this.hide();
498
- }
499
- },
500
- position: function(elem, offset){
501
- offset = offset ? $.extend({}, offset) : api.getOffsetFromBody(elem);
502
- offset.top += elem.outerHeight();
503
- errorBubble.css(offset);
504
- },
505
- show: function(){
506
- if(errorBubble.css('display') === 'none'){
507
- errorBubble.css({opacity: 0}).show();
508
- }
509
- errorBubble.addClass('va-visible').fadeTo(400, 1);
510
- },
511
- hide: function(){
512
- errorBubble.removeClass('va-visible').fadeOut();
513
- },
514
- clear: function(){
515
- clearTimeout(focusTimer);
516
- clearTimeout(hideTimer);
517
- $(document).unbind('.validityalert');
518
- $(window).unbind('.validityalert');
519
- errorBubble.stop().removeAttr('for');
520
- },
521
- _create: function(){
522
- if(errorBubble){return;}
523
- errorBubble = api.errorBubble = $('<'+alertElem+' class="validity-alert-wrapper" role="alert"><span class="validity-alert"><span class="va-arrow"><span class="va-arrow-box"></span></span><span class="va-box"></span></span></'+alertElem+'>').css({position: 'absolute', display: 'none'});
524
- webshims.ready('DOM', function(){
525
- errorBubble.appendTo('body');
526
- if($.fn.bgIframe && $.browser.msie && parseInt($.browser.version, 10) < 7){
527
- errorBubble.bgIframe();
528
- }
529
- });
530
- }
531
- };
532
-
533
-
534
- boundHide = $.proxy(api, 'hide');
535
-
536
- return api;
537
- })();
538
-
539
-
540
- /* extension, but also used to fix native implementation workaround/bugfixes */
541
- (function(){
542
- var firstEvent,
543
- invalids = [],
544
- stopSubmitTimer,
545
- form
546
- ;
547
-
548
- $(document).on('invalid', function(e){
549
- if(e.wrongWebkitInvalid){return;}
550
- var jElm = $(e.target);
551
- var shadowElem = jElm.getShadowElement();
552
- if(!shadowElem.hasClass(invalidClass)){
553
- shadowElem.addClass(invalidClasses).removeClass(validClasses);
554
- setTimeout(function(){
555
- $(e.target).trigger('changedinvalid').trigger('changedvaliditystate');
556
- }, 0);
557
- }
558
-
559
- if(!firstEvent){
560
- //trigger firstinvalid
561
- firstEvent = $.Event('firstinvalid');
562
- firstEvent.isInvalidUIPrevented = e.isDefaultPrevented;
563
- var firstSystemInvalid = $.Event('firstinvalidsystem');
564
- $(document).triggerHandler(firstSystemInvalid, {element: e.target, form: e.target.form, isInvalidUIPrevented: e.isDefaultPrevented});
565
- jElm.trigger(firstEvent);
566
- }
567
-
568
- //if firstinvalid was prevented all invalids will be also prevented
569
- if( firstEvent && firstEvent.isDefaultPrevented() ){
570
- e.preventDefault();
571
- }
572
- invalids.push(e.target);
573
- e.extraData = 'fix';
574
- clearTimeout(stopSubmitTimer);
575
- stopSubmitTimer = setTimeout(function(){
576
- var lastEvent = {type: 'lastinvalid', cancelable: false, invalidlist: $(invalids)};
577
- //reset firstinvalid
578
- firstEvent = false;
579
- invalids = [];
580
- $(e.target).trigger(lastEvent, lastEvent);
581
- }, 9);
582
- jElm = null;
583
- shadowElem = null;
584
- });
585
- })();
586
-
587
- $.fn.getErrorMessage = function(){
588
- var message = '';
589
- var elem = this[0];
590
- if(elem){
591
- message = getContentValidationMessage(elem) || $.prop(elem, 'customValidationMessage') || $.prop(elem, 'validationMessage');
592
- }
593
- return message;
594
- };
595
-
596
- if(options.replaceValidationUI){
597
- webshims.ready('DOM forms', function(){
598
- $(document).on('firstinvalid', function(e){
599
- if(!e.isInvalidUIPrevented()){
600
- e.preventDefault();
601
- $.webshims.validityAlert.showFor( e.target, $(e.target).prop('customValidationMessage') );
602
- }
603
- });
604
- });
605
- }
606
-
607
- });
608
- jQuery.webshims.register('form-native-extend', function($, webshims, window, doc, undefined, options){
609
- "use strict";
610
- var Modernizr = window.Modernizr;
611
- var modernizrInputTypes = Modernizr.inputtypes;
612
- if(!Modernizr.formvalidation || webshims.bugs.bustedValidity){return;}
613
- var typeModels = webshims.inputTypes;
614
- var validityRules = {};
615
-
616
- webshims.addInputType = function(type, obj){
617
- typeModels[type] = obj;
618
- };
619
-
620
- webshims.addValidityRule = function(type, fn){
621
- validityRules[type] = fn;
622
- };
623
-
624
- webshims.addValidityRule('typeMismatch',function (input, val, cache, validityState){
625
- if(val === ''){return false;}
626
- var ret = validityState.typeMismatch;
627
- if(!('type' in cache)){
628
- cache.type = (input[0].getAttribute('type') || '').toLowerCase();
629
- }
630
-
631
- if(typeModels[cache.type] && typeModels[cache.type].mismatch){
632
- ret = typeModels[cache.type].mismatch(val, input);
633
- }
634
- return ret;
635
- });
636
-
637
- var overrideNativeMessages = options.overrideMessages;
638
-
639
- var overrideValidity = (!modernizrInputTypes.number || !modernizrInputTypes.time || !modernizrInputTypes.range || overrideNativeMessages);
640
- var validityProps = ['customError','typeMismatch','rangeUnderflow','rangeOverflow','stepMismatch','tooLong','patternMismatch','valueMissing','valid'];
641
-
642
- var validityChanger = (overrideNativeMessages)? ['value', 'checked'] : ['value'];
643
- var validityElements = [];
644
- var testValidity = function(elem, init){
645
- if(!elem){return;}
646
- var type = (elem.getAttribute && elem.getAttribute('type') || elem.type || '').toLowerCase();
647
-
648
- if(!overrideNativeMessages && !typeModels[type]){
649
- return;
650
- }
651
-
652
- if(overrideNativeMessages && !init && type == 'radio' && elem.name){
653
- $(doc.getElementsByName( elem.name )).each(function(){
654
- $.prop(this, 'validity');
655
- });
656
- } else {
657
- $.prop(elem, 'validity');
658
- }
659
- };
660
-
661
- var oldSetCustomValidity = {};
662
- ['input', 'textarea', 'select'].forEach(function(name){
663
- var desc = webshims.defineNodeNameProperty(name, 'setCustomValidity', {
664
- prop: {
665
- value: function(error){
666
- error = error+'';
667
- var elem = (name == 'input') ? $(this).getNativeElement()[0] : this;
668
- desc.prop._supvalue.call(elem, error);
669
-
670
- if(webshims.bugs.validationMessage){
671
- webshims.data(elem, 'customvalidationMessage', error);
672
- }
673
- if(overrideValidity){
674
- webshims.data(elem, 'hasCustomError', !!(error));
675
- testValidity(elem);
676
- }
677
- }
678
- }
679
- });
680
- oldSetCustomValidity[name] = desc.prop._supvalue;
681
- });
682
-
683
-
684
- if(overrideValidity || overrideNativeMessages){
685
- validityChanger.push('min');
686
- validityChanger.push('max');
687
- validityChanger.push('step');
688
- validityElements.push('input');
689
- }
690
- if(overrideNativeMessages){
691
- validityChanger.push('required');
692
- validityChanger.push('pattern');
693
- validityElements.push('select');
694
- validityElements.push('textarea');
695
- }
696
-
697
- if(overrideValidity){
698
- var stopValidity;
699
- validityElements.forEach(function(nodeName){
700
-
701
- var oldDesc = webshims.defineNodeNameProperty(nodeName, 'validity', {
702
- prop: {
703
- get: function(){
704
- if(stopValidity){return;}
705
- var elem = (nodeName == 'input') ? $(this).getNativeElement()[0] : this;
706
-
707
- var validity = oldDesc.prop._supget.call(elem);
708
-
709
- if(!validity){
710
- return validity;
711
- }
712
- var validityState = {};
713
- validityProps.forEach(function(prop){
714
- validityState[prop] = validity[prop];
715
- });
716
-
717
- if( !$.prop(elem, 'willValidate') ){
718
- return validityState;
719
- }
720
- stopValidity = true;
721
- var jElm = $(elem),
722
- cache = {type: (elem.getAttribute && elem.getAttribute('type') || '').toLowerCase(), nodeName: (elem.nodeName || '').toLowerCase()},
723
- val = jElm.val(),
724
- customError = !!(webshims.data(elem, 'hasCustomError')),
725
- setCustomMessage
726
- ;
727
- stopValidity = false;
728
- validityState.customError = customError;
729
-
730
- if( validityState.valid && validityState.customError ){
731
- validityState.valid = false;
732
- } else if(!validityState.valid) {
733
- var allFalse = true;
734
- $.each(validityState, function(name, prop){
735
- if(prop){
736
- allFalse = false;
737
- return false;
738
- }
739
- });
740
-
741
- if(allFalse){
742
- validityState.valid = true;
743
- }
744
-
745
- }
746
-
747
- $.each(validityRules, function(rule, fn){
748
- validityState[rule] = fn(jElm, val, cache, validityState);
749
- if( validityState[rule] && (validityState.valid || !setCustomMessage) && (overrideNativeMessages || (typeModels[cache.type] && typeModels[cache.type].mismatch)) ) {
750
- oldSetCustomValidity[nodeName].call(elem, webshims.createValidationMessage(elem, rule));
751
- validityState.valid = false;
752
- setCustomMessage = true;
753
- }
754
- });
755
- if(validityState.valid){
756
- oldSetCustomValidity[nodeName].call(elem, '');
757
- webshims.data(elem, 'hasCustomError', false);
758
- } else if(overrideNativeMessages && !setCustomMessage && !customError){
759
- $.each(validityState, function(name, prop){
760
- if(name !== 'valid' && prop){
761
- oldSetCustomValidity[nodeName].call(elem, webshims.createValidationMessage(elem, name));
762
- return false;
763
- }
764
- });
765
- }
766
- return validityState;
767
- },
768
- writeable: false
769
-
770
- }
771
- });
772
- });
773
-
774
- validityChanger.forEach(function(prop){
775
- webshims.onNodeNamesPropertyModify(validityElements, prop, function(s){
776
- testValidity(this);
777
- });
778
- });
779
-
780
- if(doc.addEventListener){
781
- var inputThrottle;
782
- var testPassValidity = function(e){
783
- if(!('form' in e.target)){return;}
784
- var form = e.target.form;
785
- clearTimeout(inputThrottle);
786
- testValidity(e.target);
787
- if(form && overrideNativeMessages){
788
- $('input', form).each(function(){
789
- if(this.type == 'password'){
790
- testValidity(this);
791
- }
792
- });
793
- }
794
- };
795
-
796
- doc.addEventListener('change', testPassValidity, true);
797
-
798
- if(overrideNativeMessages){
799
- doc.addEventListener('blur', testPassValidity, true);
800
- doc.addEventListener('keydown', function(e){
801
- if(e.keyCode != 13){return;}
802
- testPassValidity(e);
803
- }, true);
804
- }
805
-
806
- doc.addEventListener('input', function(e){
807
- clearTimeout(inputThrottle);
808
- inputThrottle = setTimeout(function(){
809
- testValidity(e.target);
810
- }, 290);
811
- }, true);
812
- }
813
-
814
- var validityElementsSel = validityElements.join(',');
815
-
816
- webshims.addReady(function(context, elem){
817
- $(validityElementsSel, context).add(elem.filter(validityElementsSel)).each(function(){
818
- $.prop(this, 'validity');
819
- });
820
- });
821
-
822
-
823
- if(overrideNativeMessages){
824
- webshims.ready('DOM form-message', function(){
825
- webshims.activeLang({
826
- register: 'form-core',
827
- callback: function(){
828
- $('input, select, textarea')
829
- .getNativeElement()
830
- .each(function(){
831
- if(webshims.data(this, 'hasCustomError')){return;}
832
- var elem = this;
833
- var validity = $.prop(elem, 'validity') || {valid: true};
834
- var nodeName;
835
- if(validity.valid){return;}
836
- nodeName = (elem.nodeName || '').toLowerCase();
837
- $.each(validity, function(name, prop){
838
- if(name !== 'valid' && prop){
839
- oldSetCustomValidity[nodeName].call(elem, webshims.createValidationMessage(elem, name));
840
- return false;
841
- }
842
- });
843
- })
844
- ;
845
- }
846
- });
847
- });
848
- }
849
-
850
- } //end: overrideValidity
851
-
852
- webshims.defineNodeNameProperty('input', 'type', {
853
- prop: {
854
- get: function(){
855
- var elem = this;
856
- var type = (elem.getAttribute('type') || '').toLowerCase();
857
- return (webshims.inputTypes[type]) ? type : elem.type;
858
- }
859
- }
860
- });
861
-
862
-
863
- });
864
- jQuery.webshims.register('form-message', function($, webshims, window, document, undefined, options){
865
- "use strict";
866
- var validityMessages = webshims.validityMessages;
867
-
868
- var implementProperties = (options.overrideMessages || options.customMessages) ? ['customValidationMessage'] : [];
869
-
870
- validityMessages['en'] = $.extend(true, {
871
- typeMismatch: {
872
- email: 'Please enter an email address.',
873
- url: 'Please enter a URL.',
874
- number: 'Please enter a number.',
875
- date: 'Please enter a date.',
876
- time: 'Please enter a time.',
877
- range: 'Invalid input.',
878
- "datetime-local": 'Please enter a datetime.'
879
- },
880
- rangeUnderflow: {
881
- defaultMessage: 'Value must be greater than or equal to {%min}.'
882
- },
883
- rangeOverflow: {
884
- defaultMessage: 'Value must be less than or equal to {%max}.'
885
- },
886
- stepMismatch: 'Invalid input.',
887
- tooLong: 'Please enter at most {%maxlength} character(s). You entered {%valueLen}.',
888
-
889
- patternMismatch: 'Invalid input. {%title}',
890
- valueMissing: {
891
- defaultMessage: 'Please fill out this field.',
892
- checkbox: 'Please check this box if you want to proceed.'
893
- }
894
- }, (validityMessages['en'] || validityMessages['en-US'] || {}));
895
-
896
-
897
- ['select', 'radio'].forEach(function(type){
898
- validityMessages['en'].valueMissing[type] = 'Please select an option.';
899
- });
900
-
901
- ['date', 'time', 'datetime-local'].forEach(function(type){
902
- validityMessages.en.rangeUnderflow[type] = 'Value must be at or after {%min}.';
903
- });
904
- ['date', 'time', 'datetime-local'].forEach(function(type){
905
- validityMessages.en.rangeOverflow[type] = 'Value must be at or before {%max}.';
906
- });
907
-
908
- validityMessages['en-US'] = validityMessages['en-US'] || validityMessages['en'];
909
- validityMessages[''] = validityMessages[''] || validityMessages['en-US'];
910
-
911
- validityMessages['de'] = $.extend(true, {
912
- typeMismatch: {
913
- email: '{%value} ist keine zulässige E-Mail-Adresse',
914
- url: '{%value} ist keine zulässige Webadresse',
915
- number: '{%value} ist keine Nummer!',
916
- date: '{%value} ist kein Datum',
917
- time: '{%value} ist keine Uhrzeit',
918
- range: '{%value} ist keine Nummer!',
919
- "datetime-local": '{%value} ist kein Datum-Uhrzeit Format.'
920
- },
921
- rangeUnderflow: {
922
- defaultMessage: '{%value} ist zu niedrig. {%min} ist der unterste Wert, den Sie benutzen können.'
923
- },
924
- rangeOverflow: {
925
- defaultMessage: '{%value} ist zu hoch. {%max} ist der oberste Wert, den Sie benutzen können.'
926
- },
927
- stepMismatch: 'Der Wert {%value} ist in diesem Feld nicht zulässig. Hier sind nur bestimmte Werte zulässig. {%title}',
928
- tooLong: 'Der eingegebene Text ist zu lang! Sie haben {%valueLen} Zeichen eingegeben, dabei sind {%maxlength} das Maximum.',
929
- patternMismatch: '{%value} hat für dieses Eingabefeld ein falsches Format! {%title}',
930
- valueMissing: {
931
- defaultMessage: 'Bitte geben Sie einen Wert ein',
932
- checkbox: 'Bitte aktivieren Sie das Kästchen'
933
- }
934
- }, (validityMessages['de'] || {}));
935
-
936
- ['select', 'radio'].forEach(function(type){
937
- validityMessages['de'].valueMissing[type] = 'Bitte wählen Sie eine Option aus';
938
- });
939
-
940
- ['date', 'time', 'datetime-local'].forEach(function(type){
941
- validityMessages.de.rangeUnderflow[type] = '{%value} ist zu früh. {%min} ist die früheste Zeit, die Sie benutzen können.';
942
- });
943
- ['date', 'time', 'datetime-local'].forEach(function(type){
944
- validityMessages.de.rangeOverflow[type] = '{%value} ist zu spät. {%max} ist die späteste Zeit, die Sie benutzen können.';
945
- });
946
-
947
- var currentValidationMessage = validityMessages[''];
948
-
949
-
950
- webshims.createValidationMessage = function(elem, name){
951
- var message = currentValidationMessage[name];
952
- if(message && typeof message !== 'string'){
953
- message = message[ $.prop(elem, 'type') ] || message[ (elem.nodeName || '').toLowerCase() ] || message[ 'defaultMessage' ];
954
- }
955
- if(message){
956
- ['value', 'min', 'max', 'title', 'maxlength', 'label'].forEach(function(attr){
957
- if(message.indexOf('{%'+attr) === -1){return;}
958
- var val = ((attr == 'label') ? $.trim($('label[for="'+ elem.id +'"]', elem.form).text()).replace(/\*$|:$/, '') : $.attr(elem, attr)) || '';
959
- if(name == 'patternMismatch' && attr == 'title' && !val){
960
- webshims.error('no title for patternMismatch provided. Always add a title attribute.');
961
- }
962
- message = message.replace('{%'+ attr +'}', val);
963
- if('value' == attr){
964
- message = message.replace('{%valueLen}', val.length);
965
- }
966
- });
967
- }
968
- return message || '';
969
- };
970
-
971
-
972
- if(webshims.bugs.validationMessage || !Modernizr.formvalidation || webshims.bugs.bustedValidity){
973
- implementProperties.push('validationMessage');
974
- }
975
-
976
- webshims.activeLang({
977
- langObj: validityMessages,
978
- module: 'form-core',
979
- callback: function(langObj){
980
- currentValidationMessage = langObj;
981
- }
982
- });
983
-
984
- implementProperties.forEach(function(messageProp){
985
- webshims.defineNodeNamesProperty(['fieldset', 'output', 'button'], messageProp, {
986
- prop: {
987
- value: '',
988
- writeable: false
989
- }
990
- });
991
- ['input', 'select', 'textarea'].forEach(function(nodeName){
992
- var desc = webshims.defineNodeNameProperty(nodeName, messageProp, {
993
- prop: {
994
- get: function(){
995
- var elem = this;
996
- var message = '';
997
- if(!$.prop(elem, 'willValidate')){
998
- return message;
999
- }
1000
-
1001
- var validity = $.prop(elem, 'validity') || {valid: 1};
1002
-
1003
- if(validity.valid){return message;}
1004
- message = webshims.getContentValidationMessage(elem, validity);
1005
-
1006
- if(message){return message;}
1007
-
1008
- if(validity.customError && elem.nodeName){
1009
- message = (Modernizr.formvalidation && !webshims.bugs.bustedValidity && desc.prop._supget) ? desc.prop._supget.call(elem) : webshims.data(elem, 'customvalidationMessage');
1010
- if(message){return message;}
1011
- }
1012
- $.each(validity, function(name, prop){
1013
- if(name == 'valid' || !prop){return;}
1014
-
1015
- message = webshims.createValidationMessage(elem, name);
1016
- if(message){
1017
- return false;
1018
- }
1019
- });
1020
- return message || '';
1021
- },
1022
- writeable: false
1023
- }
1024
- });
1025
- });
1026
-
1027
- });
1028
- });
1029
- jQuery.webshims.register('form-datalist', function($, webshims, window, document, undefined){
1030
- "use strict";
1031
- var doc = document;
1032
-
1033
- /*
1034
- * implement propType "element" currently only used for list-attribute (will be moved to dom-extend, if needed)
1035
- */
1036
- webshims.propTypes.element = function(descs){
1037
- webshims.createPropDefault(descs, 'attr');
1038
- if(descs.prop){return;}
1039
- descs.prop = {
1040
- get: function(){
1041
- var elem = descs.attr.get.call(this);
1042
- if(elem){
1043
- elem = document.getElementById(elem);
1044
- if(elem && descs.propNodeName && !$.nodeName(elem, descs.propNodeName)){
1045
- elem = null;
1046
- }
1047
- }
1048
- return elem || null;
1049
- },
1050
- writeable: false
1051
- };
1052
- };
1053
-
1054
-
1055
- /*
1056
- * Implements datalist element and list attribute
1057
- */
1058
-
1059
- (function(){
1060
- var formsCFG = $.webshims.cfg.forms;
1061
- var listSupport = Modernizr.input.list;
1062
- if(listSupport && !formsCFG.customDatalist){return;}
1063
-
1064
- var initializeDatalist = function(){
1065
-
1066
-
1067
- if(!listSupport){
1068
- webshims.defineNodeNameProperty('datalist', 'options', {
1069
- prop: {
1070
- writeable: false,
1071
- get: function(){
1072
- var elem = this;
1073
- var select = $('select', elem);
1074
- var options;
1075
- if(select[0]){
1076
- options = select[0].options;
1077
- } else {
1078
- options = $('option', elem).get();
1079
- if(options.length){
1080
- webshims.warn('you should wrap your option-elements for a datalist in a select element to support IE and other old browsers.');
1081
- }
1082
- }
1083
- return options;
1084
- }
1085
- }
1086
- });
1087
- }
1088
-
1089
- var inputListProto = {
1090
- //override autocomplete
1091
- autocomplete: {
1092
- attr: {
1093
- get: function(){
1094
- var elem = this;
1095
- var data = $.data(elem, 'datalistWidget');
1096
- if(data){
1097
- return data._autocomplete;
1098
- }
1099
- return ('autocomplete' in elem) ? elem.autocomplete : elem.getAttribute('autocomplete');
1100
- },
1101
- set: function(value){
1102
- var elem = this;
1103
- var data = $.data(elem, 'datalistWidget');
1104
- if(data){
1105
- data._autocomplete = value;
1106
- if(value == 'off'){
1107
- data.hideList();
1108
- }
1109
- } else {
1110
- if('autocomplete' in elem){
1111
- elem.autocomplete = value;
1112
- } else {
1113
- elem.setAttribute('autocomplete', value);
1114
- }
1115
- }
1116
- }
1117
- }
1118
- }
1119
- };
1120
-
1121
- // if(formsCFG.customDatalist && (!listSupport || !('selectedOption') in $('<input />')[0])){
1122
- // //currently not supported x-browser (FF4 has not implemented and is not polyfilled )
1123
- // inputListProto.selectedOption = {
1124
- // prop: {
1125
- // writeable: false,
1126
- // get: function(){
1127
- // var elem = this;
1128
- // var list = $.prop(elem, 'list');
1129
- // var ret = null;
1130
- // var value, options;
1131
- // if(!list){return ret;}
1132
- // value = $.prop(elem, 'value');
1133
- // if(!value){return ret;}
1134
- // options = $.prop(list, 'options');
1135
- // if(!options.length){return ret;}
1136
- // $.each(options, function(i, option){
1137
- // if(value == $.prop(option, 'value')){
1138
- // ret = option;
1139
- // return false;
1140
- // }
1141
- // });
1142
- // return ret;
1143
- // }
1144
- // }
1145
- // };
1146
- // }
1147
-
1148
- if(!listSupport){
1149
- inputListProto['list'] = {
1150
- attr: {
1151
- get: function(){
1152
- var val = webshims.contentAttr(this, 'list');
1153
- return (val == null) ? undefined : val;
1154
- },
1155
- set: function(value){
1156
- var elem = this;
1157
- webshims.contentAttr(elem, 'list', value);
1158
- webshims.objectCreate(shadowListProto, undefined, {input: elem, id: value, datalist: $.prop(elem, 'list')});
1159
- }
1160
- },
1161
- initAttr: true,
1162
- reflect: true,
1163
- propType: 'element',
1164
- propNodeName: 'datalist'
1165
- };
1166
- } else {
1167
- //options only return options, if option-elements are rooted: but this makes this part of HTML5 less backwards compatible
1168
- if(!($('<datalist><select><option></option></select></datalist>').prop('options') || []).length ){
1169
- webshims.defineNodeNameProperty('datalist', 'options', {
1170
- prop: {
1171
- writeable: false,
1172
- get: function(){
1173
- var options = this.options || [];
1174
- if(!options.length){
1175
- var elem = this;
1176
- var select = $('select', elem);
1177
- if(select[0] && select[0].options && select[0].options.length){
1178
- options = select[0].options;
1179
- }
1180
- }
1181
- return options;
1182
- }
1183
- }
1184
- });
1185
- }
1186
- inputListProto['list'] = {
1187
- attr: {
1188
- get: function(){
1189
- var val = webshims.contentAttr(this, 'list');
1190
- if(val != null){
1191
- this.removeAttribute('list');
1192
- } else {
1193
- val = $.data(this, 'datalistListAttr');
1194
- }
1195
-
1196
- return (val == null) ? undefined : val;
1197
- },
1198
- set: function(value){
1199
- var elem = this;
1200
- $.data(elem, 'datalistListAttr', value);
1201
- webshims.objectCreate(shadowListProto, undefined, {input: elem, id: value, datalist: $.prop(elem, 'list')});
1202
- }
1203
- },
1204
- initAttr: true,
1205
- reflect: true,
1206
- propType: 'element',
1207
- propNodeName: 'datalist'
1208
- };
1209
- }
1210
-
1211
-
1212
- webshims.defineNodeNameProperties('input', inputListProto);
1213
-
1214
- if($.event.customEvent){
1215
- $.event.customEvent.updateDatalist = true;
1216
- $.event.customEvent.updateInput = true;
1217
- $.event.customEvent.datalistselect = true;
1218
- }
1219
- webshims.addReady(function(context, contextElem){
1220
- contextElem
1221
- .filter('datalist > select, datalist, datalist > option, datalist > select > option')
1222
- .closest('datalist')
1223
- .triggerHandler('updateDatalist')
1224
- ;
1225
-
1226
- });
1227
-
1228
-
1229
- };
1230
-
1231
-
1232
- /*
1233
- * ShadowList
1234
- */
1235
- var listidIndex = 0;
1236
-
1237
- var noDatalistSupport = {
1238
- submit: 1,
1239
- button: 1,
1240
- reset: 1,
1241
- hidden: 1,
1242
-
1243
- //ToDo
1244
- range: 1,
1245
- date: 1
1246
- };
1247
- var lteie6 = ($.browser.msie && parseInt($.browser.version, 10) < 7);
1248
- var globStoredOptions = {};
1249
- var getStoredOptions = function(name){
1250
- if(!name){return [];}
1251
- if(globStoredOptions[name]){
1252
- return globStoredOptions[name];
1253
- }
1254
- var data;
1255
- try {
1256
- data = JSON.parse(localStorage.getItem('storedDatalistOptions'+name));
1257
- } catch(e){}
1258
- globStoredOptions[name] = data || [];
1259
- return data || [];
1260
- };
1261
- var storeOptions = function(name, val){
1262
- if(!name){return;}
1263
- val = val || [];
1264
- try {
1265
- localStorage.setItem( 'storedDatalistOptions'+name, JSON.stringify(val) );
1266
- } catch(e){}
1267
- };
1268
-
1269
- var getText = function(elem){
1270
- return (elem.textContent || elem.innerText || $.text([ elem ]) || '');
1271
- };
1272
-
1273
- var shadowListProto = {
1274
- _create: function(opts){
1275
-
1276
- if(noDatalistSupport[$.prop(opts.input, 'type')]){return;}
1277
- var datalist = opts.datalist;
1278
- var data = $.data(opts.input, 'datalistWidget');
1279
- if(datalist && data && data.datalist !== datalist){
1280
- data.datalist = datalist;
1281
- data.id = opts.id;
1282
-
1283
- data.shadowList.prop('className', 'datalist-polyfill '+ (data.datalist.className || '') + ' '+ data.datalist.id +'-shadowdom');
1284
- if(formsCFG.positionDatalist){
1285
- data.shadowList.insertAfter(opts.input);
1286
- } else {
1287
- data.shadowList.appendTo('body');
1288
- }
1289
- $(data.datalist)
1290
- .off('updateDatalist.datalistWidget')
1291
- .on('updateDatalist.datalistWidget', $.proxy(data, '_resetListCached'))
1292
- ;
1293
- data._resetListCached();
1294
- return;
1295
- } else if(!datalist){
1296
- if(data){
1297
- data.destroy();
1298
- }
1299
- return;
1300
- } else if(data && data.datalist === datalist){
1301
- return;
1302
- }
1303
- listidIndex++;
1304
- var that = this;
1305
- this.hideList = $.proxy(that, 'hideList');
1306
- this.timedHide = function(){
1307
- clearTimeout(that.hideTimer);
1308
- that.hideTimer = setTimeout(that.hideList, 9);
1309
- };
1310
- this.datalist = datalist;
1311
- this.id = opts.id;
1312
- this.hasViewableData = true;
1313
- this._autocomplete = $.attr(opts.input, 'autocomplete');
1314
- $.data(opts.input, 'datalistWidget', this);
1315
- this.shadowList = $('<div class="datalist-polyfill '+ (this.datalist.className || '') + ' '+ this.datalist.id +'-shadowdom' +'" />');
1316
-
1317
- if(formsCFG.positionDatalist || $(opts.input).hasClass('position-datalist')){
1318
- this.shadowList.insertAfter(opts.input);
1319
- } else {
1320
- this.shadowList.appendTo('body');
1321
- }
1322
-
1323
- this.index = -1;
1324
- this.input = opts.input;
1325
- this.arrayOptions = [];
1326
-
1327
- this.shadowList
1328
- .delegate('li', 'mouseenter.datalistWidget mousedown.datalistWidget click.datalistWidget', function(e){
1329
- var items = $('li:not(.hidden-item)', that.shadowList);
1330
- var select = (e.type == 'mousedown' || e.type == 'click');
1331
- that.markItem(items.index(e.currentTarget), select, items);
1332
- if(e.type == 'click'){
1333
- that.hideList();
1334
- if(formsCFG.customDatalist){
1335
- $(opts.input).trigger('datalistselect');
1336
- }
1337
- }
1338
- return (e.type != 'mousedown');
1339
- })
1340
- .on('focusout', this.timedHide)
1341
- ;
1342
-
1343
- opts.input.setAttribute('autocomplete', 'off');
1344
-
1345
- $(opts.input)
1346
- .attr({
1347
- //role: 'combobox',
1348
- 'aria-haspopup': 'true'
1349
- })
1350
- .on({
1351
- 'input.datalistWidget': function(){
1352
- if(!that.triggeredByDatalist){
1353
- that.changedValue = false;
1354
- that.showHideOptions();
1355
- }
1356
- },
1357
- 'keydown.datalistWidget': function(e){
1358
- var keyCode = e.keyCode;
1359
- var activeItem;
1360
- var items;
1361
- if(keyCode == 40 && !that.showList()){
1362
- that.markItem(that.index + 1, true);
1363
- return false;
1364
- }
1365
-
1366
- if(!that.isListVisible){return;}
1367
-
1368
-
1369
- if(keyCode == 38){
1370
- that.markItem(that.index - 1, true);
1371
- return false;
1372
- }
1373
- if(!e.shiftKey && (keyCode == 33 || keyCode == 36)){
1374
- that.markItem(0, true);
1375
- return false;
1376
- }
1377
- if(!e.shiftKey && (keyCode == 34 || keyCode == 35)){
1378
- items = $('li:not(.hidden-item)', that.shadowList);
1379
- that.markItem(items.length - 1, true, items);
1380
- return false;
1381
- }
1382
- if(keyCode == 13 || keyCode == 27){
1383
- if (keyCode == 13){
1384
- activeItem = $('li.active-item:not(.hidden-item)', that.shadowList);
1385
- that.changeValue( $('li.active-item:not(.hidden-item)', that.shadowList) );
1386
- }
1387
- that.hideList();
1388
- if(formsCFG.customDatalist && activeItem && activeItem[0]){
1389
- $(opts.input).trigger('datalistselect');
1390
- }
1391
- return false;
1392
- }
1393
- },
1394
- 'focus.datalistWidget': function(){
1395
- if($(this).hasClass('list-focus')){
1396
- that.showList();
1397
- }
1398
- },
1399
- 'mousedown.datalistWidget': function(){
1400
- if($(this).is(':focus')){
1401
- that.showList();
1402
- }
1403
- },
1404
- 'blur.datalistWidget': this.timedHide
1405
- })
1406
- ;
1407
-
1408
-
1409
- $(this.datalist)
1410
- .off('updateDatalist.datalistWidget')
1411
- .on('updateDatalist.datalistWidget', $.proxy(this, '_resetListCached'))
1412
- ;
1413
-
1414
- this._resetListCached();
1415
-
1416
- if(opts.input.form && (opts.input.name || opts.input.id)){
1417
- $(opts.input.form).on('submit.datalistWidget'+opts.input.id, function(){
1418
- if(!$(opts.input).hasClass('no-datalist-cache') && that._autocomplete != 'off'){
1419
- var val = $.prop(opts.input, 'value');
1420
- var name = (opts.input.name || opts.input.id) + $.prop(opts.input, 'type');
1421
- if(!that.storedOptions){
1422
- that.storedOptions = getStoredOptions( name );
1423
- }
1424
- if(val && that.storedOptions.indexOf(val) == -1){
1425
- that.storedOptions.push(val);
1426
- storeOptions(name, that.storedOptions );
1427
- }
1428
- }
1429
- });
1430
- }
1431
- $(window).on('unload.datalist'+this.id+' beforeunload.datalist'+this.id, function(){
1432
- that.destroy();
1433
- });
1434
- },
1435
- destroy: function(){
1436
- var autocomplete = $.attr(this.input, 'autocomplete');
1437
- $(this.input)
1438
- .off('.datalistWidget')
1439
- .removeData('datalistWidget')
1440
- ;
1441
- this.shadowList.remove();
1442
- $(document).off('.datalist'+this.id);
1443
- $(window).off('.datalist'+this.id);
1444
- if(this.input.form && this.input.id){
1445
- $(this.input.form).off('submit.datalistWidget'+this.input.id);
1446
- }
1447
- this.input.removeAttribute('aria-haspopup');
1448
- if(autocomplete === undefined){
1449
- this.input.removeAttribute('autocomplete');
1450
- } else {
1451
- $(this.input).attr('autocomplete', autocomplete);
1452
- }
1453
- },
1454
- _resetListCached: function(e){
1455
- var that = this;
1456
- var forceShow;
1457
- this.needsUpdate = true;
1458
- this.lastUpdatedValue = false;
1459
- this.lastUnfoundValue = '';
1460
-
1461
- if(!this.updateTimer){
1462
- if(window.QUnit || (forceShow = (e && document.activeElement == that.input))){
1463
- that.updateListOptions(forceShow);
1464
- } else {
1465
- webshims.ready('WINDOWLOAD', function(){
1466
- that.updateTimer = setTimeout(function(){
1467
- that.updateListOptions();
1468
- that = null;
1469
- listidIndex = 1;
1470
- }, 200 + (100 * listidIndex));
1471
- });
1472
- }
1473
- }
1474
- },
1475
- maskHTML: function(str){
1476
- return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
1477
- },
1478
- updateListOptions: function(_forceShow){
1479
- this.needsUpdate = false;
1480
- clearTimeout(this.updateTimer);
1481
- this.updateTimer = false;
1482
- this.shadowList
1483
- .css({
1484
- fontSize: $.css(this.input, 'fontSize'),
1485
- fontFamily: $.css(this.input, 'fontFamily')
1486
- })
1487
- ;
1488
- this.searchStart = formsCFG.customDatalist && $(this.input).hasClass('search-start');
1489
-
1490
- var list = [];
1491
-
1492
- var values = [];
1493
- var allOptions = [];
1494
- var rElem, rItem, rOptions, rI, rLen, item;
1495
- for(rOptions = $.prop(this.datalist, 'options'), rI = 0, rLen = rOptions.length; rI < rLen; rI++){
1496
- rElem = rOptions[rI];
1497
- if(rElem.disabled){return;}
1498
- rItem = {
1499
- value: $(rElem).val() || '',
1500
- text: $.trim($.attr(rElem, 'label') || getText(rElem)),
1501
- className: rElem.className || '',
1502
- style: $.attr(rElem, 'style') || ''
1503
- };
1504
- if(!rItem.text){
1505
- rItem.text = rItem.value;
1506
- } else if(rItem.text != rItem.value){
1507
- rItem.className += ' different-label-value';
1508
- }
1509
- values[rI] = rItem.value;
1510
- allOptions[rI] = rItem;
1511
- }
1512
-
1513
- if(!this.storedOptions){
1514
- this.storedOptions = ($(this.input).hasClass('no-datalist-cache') || this._autocomplete == 'off') ? [] : getStoredOptions((this.input.name || this.input.id) + $.prop(this.input, 'type'));
1515
- }
1516
-
1517
- this.storedOptions.forEach(function(val, i){
1518
- if(values.indexOf(val) == -1){
1519
- allOptions.push({value: val, text: val, className: 'stored-suggest', style: ''});
1520
- }
1521
- });
1522
-
1523
- for(rI = 0, rLen = allOptions.length; rI < rLen; rI++){
1524
- item = allOptions[rI];
1525
- 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>';
1526
- }
1527
-
1528
- this.arrayOptions = allOptions;
1529
- this.shadowList.html('<div class="datalist-outer-box"><div class="datalist-box"><ul role="list">'+ list.join("\n") +'</ul></div></div>');
1530
-
1531
- if($.fn.bgIframe && lteie6){
1532
- this.shadowList.bgIframe();
1533
- }
1534
-
1535
- if(_forceShow || this.isListVisible){
1536
- this.showHideOptions();
1537
- }
1538
- },
1539
- showHideOptions: function(_fromShowList){
1540
- var value = $.prop(this.input, 'value').toLowerCase();
1541
- //first check prevent infinite loop, second creates simple lazy optimization
1542
- if(value === this.lastUpdatedValue || (this.lastUnfoundValue && value.indexOf(this.lastUnfoundValue) === 0)){
1543
- return;
1544
- }
1545
-
1546
- this.lastUpdatedValue = value;
1547
- var found = false;
1548
- var startSearch = this.searchStart;
1549
- var lis = $('li', this.shadowList);
1550
- if(value){
1551
- this.arrayOptions.forEach(function(item, i){
1552
- var search;
1553
- if(!('lowerText' in item)){
1554
- if(item.text != item.value){
1555
- item.lowerText = item.value.toLowerCase() + item.text.toLowerCase();
1556
- } else {
1557
- item.lowerText = item.text.toLowerCase();
1558
- }
1559
- }
1560
- search = item.lowerText.indexOf(value);
1561
- search = startSearch ? !search : search !== -1;
1562
- if(search){
1563
- $(lis[i]).removeClass('hidden-item');
1564
- found = true;
1565
- } else {
1566
- $(lis[i]).addClass('hidden-item');
1567
- }
1568
- });
1569
- } else if(lis.length) {
1570
- lis.removeClass('hidden-item');
1571
- found = true;
1572
- }
1573
-
1574
- this.hasViewableData = found;
1575
- if(!_fromShowList && found){
1576
- this.showList();
1577
- }
1578
- if(!found){
1579
- this.lastUnfoundValue = value;
1580
- this.hideList();
1581
- }
1582
- },
1583
- setPos: function(){
1584
- this.shadowList.css({marginTop: 0, marginLeft: 0, marginRight: 0, marginBottom: 0});
1585
- var css = (formsCFG.positionDatalist) ? $(this.input).position() : webshims.getRelOffset(this.shadowList, this.input);
1586
- css.top += $(this.input).outerHeight();
1587
- css.width = $(this.input).outerWidth() - (parseInt(this.shadowList.css('borderLeftWidth'), 10) || 0) - (parseInt(this.shadowList.css('borderRightWidth'), 10) || 0);
1588
- this.shadowList.css({marginTop: '', marginLeft: '', marginRight: '', marginBottom: ''}).css(css);
1589
- return css;
1590
- },
1591
- showList: function(){
1592
- if(this.isListVisible){return false;}
1593
- if(this.needsUpdate){
1594
- this.updateListOptions();
1595
- }
1596
- this.showHideOptions(true);
1597
- if(!this.hasViewableData){return false;}
1598
- this.isListVisible = true;
1599
- var that = this;
1600
-
1601
- that.setPos();
1602
- that.shadowList.addClass('datalist-visible').find('li.active-item').removeClass('active-item');
1603
-
1604
- $(window).unbind('.datalist'+that.id);
1605
- $(document)
1606
- .off('.datalist'+that.id)
1607
- .on('mousedown.datalist'+that.id +' focusin.datalist'+that.id, function(e){
1608
- if(e.target === that.input || that.shadowList[0] === e.target || $.contains( that.shadowList[0], e.target )){
1609
- clearTimeout(that.hideTimer);
1610
- setTimeout(function(){
1611
- clearTimeout(that.hideTimer);
1612
- }, 9);
1613
- } else {
1614
- that.timedHide();
1615
- }
1616
- })
1617
- .on('updateshadowdom.datalist'+that.id, function(){
1618
- that.setPos();
1619
- })
1620
- ;
1621
- return true;
1622
- },
1623
- hideList: function(){
1624
- if(!this.isListVisible){return false;}
1625
- var that = this;
1626
- var triggerChange = function(e){
1627
- if(that.changedValue){
1628
- $(that.input).trigger('change');
1629
- }
1630
- that.changedValue = false;
1631
- };
1632
-
1633
- that.shadowList.removeClass('datalist-visible list-item-active');
1634
- that.index = -1;
1635
- that.isListVisible = false;
1636
- if(that.changedValue){
1637
- that.triggeredByDatalist = true;
1638
- webshims.triggerInlineForm && webshims.triggerInlineForm(that.input, 'input');
1639
- if($(that.input).is(':focus')){
1640
- $(that.input).one('blur', triggerChange);
1641
- } else {
1642
- triggerChange();
1643
- }
1644
- that.triggeredByDatalist = false;
1645
- }
1646
- $(document).unbind('.datalist'+that.id);
1647
- $(window)
1648
- .off('.datalist'+that.id)
1649
- .one('resize.datalist'+that.id, function(){
1650
- that.shadowList.css({top: 0, left: 0});
1651
- })
1652
- ;
1653
- return true;
1654
- },
1655
- scrollIntoView: function(elem){
1656
- var ul = $('ul', this.shadowList);
1657
- var div = $('div.datalist-box', this.shadowList);
1658
- var elemPos = elem.position();
1659
- var containerHeight;
1660
- elemPos.top -= (parseInt(ul.css('paddingTop'), 10) || 0) + (parseInt(ul.css('marginTop'), 10) || 0) + (parseInt(ul.css('borderTopWidth'), 10) || 0);
1661
- if(elemPos.top < 0){
1662
- div.scrollTop( div.scrollTop() + elemPos.top - 2);
1663
- return;
1664
- }
1665
- elemPos.top += elem.outerHeight();
1666
- containerHeight = div.height();
1667
- if(elemPos.top > containerHeight){
1668
- div.scrollTop( div.scrollTop() + (elemPos.top - containerHeight) + 2);
1669
- }
1670
- },
1671
- changeValue: function(activeItem){
1672
- if(!activeItem[0]){return;}
1673
- var newValue = $('span.option-value', activeItem).text();
1674
- var oldValue = $.prop(this.input, 'value');
1675
- if(newValue != oldValue){
1676
- $(this.input)
1677
- .prop('value', newValue)
1678
- .triggerHandler('updateInput')
1679
- ;
1680
- this.changedValue = true;
1681
- }
1682
- },
1683
- markItem: function(index, doValue, items){
1684
- var activeItem;
1685
- var goesUp;
1686
-
1687
- items = items || $('li:not(.hidden-item)', this.shadowList);
1688
- if(!items.length){return;}
1689
- if(index < 0){
1690
- index = items.length - 1;
1691
- } else if(index >= items.length){
1692
- index = 0;
1693
- }
1694
- items.removeClass('active-item');
1695
- this.shadowList.addClass('list-item-active');
1696
- activeItem = items.filter(':eq('+ index +')').addClass('active-item');
1697
-
1698
- if(doValue){
1699
- this.changeValue(activeItem);
1700
- this.scrollIntoView(activeItem);
1701
- }
1702
- this.index = index;
1703
- }
1704
- };
1705
-
1706
- //init datalist update
1707
- initializeDatalist();
1708
- })();
1709
-
1
+ //additional tests for partial implementation of forms features
2
+ (function($){
3
+ "use strict";
4
+ var Modernizr = window.Modernizr;
5
+ var webshims = $.webshims;
6
+ var bugs = webshims.bugs;
7
+ var form = $('<form action="#" style="width: 1px; height: 1px; overflow: hidden;"><select name="b" required="" /><input required="" name="a" /></form>');
8
+ var testRequiredFind = function(){
9
+ if(form[0].querySelector){
10
+ try {
11
+ bugs.findRequired = !(form[0].querySelector('select:required'));
12
+ } catch(er){
13
+ bugs.findRequired = false;
14
+ }
15
+ }
16
+ };
17
+ var inputElem = $('input', form).eq(0);
18
+ var onDomextend = function(fn){
19
+ webshims.loader.loadList(['dom-extend']);
20
+ webshims.ready('dom-extend', fn);
21
+ };
22
+
23
+ bugs.findRequired = false;
24
+ bugs.validationMessage = false;
25
+
26
+ webshims.capturingEventPrevented = function(e){
27
+ if(!e._isPolyfilled){
28
+ var isDefaultPrevented = e.isDefaultPrevented;
29
+ var preventDefault = e.preventDefault;
30
+ e.preventDefault = function(){
31
+ clearTimeout($.data(e.target, e.type + 'DefaultPrevented'));
32
+ $.data(e.target, e.type + 'DefaultPrevented', setTimeout(function(){
33
+ $.removeData(e.target, e.type + 'DefaultPrevented');
34
+ }, 30));
35
+ return preventDefault.apply(this, arguments);
36
+ };
37
+ e.isDefaultPrevented = function(){
38
+ return !!(isDefaultPrevented.apply(this, arguments) || $.data(e.target, e.type + 'DefaultPrevented') || false);
39
+ };
40
+ e._isPolyfilled = true;
41
+ }
42
+ };
43
+
44
+ if(!Modernizr.formvalidation || bugs.bustedValidity){
45
+ testRequiredFind();
46
+ return;
47
+ }
48
+
49
+ //create delegatable events
50
+ webshims.capturingEvents(['input']);
51
+ webshims.capturingEvents(['invalid'], true);
52
+
53
+ if(window.opera || window.testGoodWithFix){
54
+
55
+ form.appendTo('head');
56
+
57
+ testRequiredFind();
58
+ bugs.validationMessage = !(inputElem.prop('validationMessage'));
59
+
60
+ webshims.reTest(['form-native-extend', 'form-message']);
61
+
62
+ form.remove();
63
+
64
+ $(function(){
65
+ onDomextend(function(){
66
+
67
+ //Opera shows native validation bubbles in case of input.checkValidity()
68
+ // Opera 11.6/12 hasn't fixed this issue right, it's buggy
69
+ var preventDefault = function(e){
70
+ e.preventDefault();
71
+ };
72
+
73
+ ['form', 'input', 'textarea', 'select'].forEach(function(name){
74
+ var desc = webshims.defineNodeNameProperty(name, 'checkValidity', {
75
+ prop: {
76
+ value: function(){
77
+ if (!webshims.fromSubmit) {
78
+ $(this).on('invalid.checkvalidity', preventDefault);
79
+ }
80
+
81
+ webshims.fromCheckValidity = true;
82
+ var ret = desc.prop._supvalue.apply(this, arguments);
83
+ if (!webshims.fromSubmit) {
84
+ $(this).unbind('invalid.checkvalidity', preventDefault);
85
+ }
86
+ webshims.fromCheckValidity = false;
87
+ return ret;
88
+ }
89
+ }
90
+ });
91
+ });
92
+
93
+ });
94
+ });
95
+ }
96
+
97
+ if($.browser.webkit && !webshims.bugs.bustedValidity){
98
+ (function(){
99
+ var elems = /^(?:textarea|input)$/i;
100
+ var form = false;
101
+
102
+ document.addEventListener('contextmenu', function(e){
103
+ if(elems.test( e.target.nodeName || '') && (form = e.target.form)){
104
+ setTimeout(function(){
105
+ form = false;
106
+ }, 1);
107
+ }
108
+ }, false);
109
+
110
+ $(window).on('invalid', function(e){
111
+ if(e.originalEvent && form && form == e.target.form){
112
+ e.wrongWebkitInvalid = true;
113
+ e.stopImmediatePropagation();
114
+ }
115
+ });
116
+
117
+ })();
118
+ }
119
+ })(jQuery);
120
+
121
+ jQuery.webshims.register('form-core', function($, webshims, window, document, undefined, options){
122
+ "use strict";
123
+
124
+
125
+ var checkTypes = {checkbox: 1, radio: 1};
126
+ var emptyJ = $([]);
127
+ var bugs = webshims.bugs;
128
+ var groupTypes = {radio: 1};
129
+ var getGroupElements = function(elem){
130
+ elem = $(elem);
131
+ var name;
132
+ var form;
133
+ var ret = emptyJ;
134
+ if(groupTypes[elem[0].type]){
135
+ form = elem.prop('form');
136
+ name = elem[0].name;
137
+ if(!name){
138
+ ret = elem;
139
+ } else if(form){
140
+ ret = $(form[name]);
141
+ } else {
142
+ ret = $(document.getElementsByName(name)).filter(function(){
143
+ return !$.prop(this, 'form');
144
+ });
145
+ }
146
+ ret = ret.filter('[type="radio"]');
147
+ }
148
+ return ret;
149
+ };
150
+
151
+ var getContentValidationMessage = webshims.getContentValidationMessage = function(elem, validity, key){
152
+ var message = $(elem).data('errormessage') || elem.getAttribute('x-moz-errormessage') || '';
153
+ if(key && message[key]){
154
+ message = message[key];
155
+ }
156
+ if(typeof message == 'object'){
157
+ validity = validity || $.prop(elem, 'validity') || {valid: 1};
158
+ if(!validity.valid){
159
+ $.each(validity, function(name, prop){
160
+ if(prop && name != 'valid' && message[name]){
161
+ message = message[name];
162
+ return false;
163
+ }
164
+ });
165
+ }
166
+ }
167
+
168
+ if(typeof message == 'object'){
169
+ message = message.defaultMessage;
170
+ }
171
+ return message || '';
172
+ };
173
+
174
+ /*
175
+ * Selectors for all browsers
176
+ */
177
+ var rangeTypes = {number: 1, range: 1, date: 1/*, time: 1, 'datetime-local': 1, datetime: 1, month: 1, week: 1*/};
178
+ var hasInvalid = function(elem){
179
+ var ret = false;
180
+ $($.prop(elem, 'elements')).each(function(){
181
+ ret = $(this).is(':invalid');
182
+ if(ret){
183
+ return false;
184
+ }
185
+ });
186
+ return ret;
187
+ };
188
+ $.extend($.expr[":"], {
189
+ "valid-element": function(elem){
190
+ return $.nodeName(elem, 'form') ? !hasInvalid(elem) :!!($.prop(elem, 'willValidate') && isValid(elem));
191
+ },
192
+ "invalid-element": function(elem){
193
+ return $.nodeName(elem, 'form') ? hasInvalid(elem) : !!($.prop(elem, 'willValidate') && !isValid(elem));
194
+ },
195
+ "required-element": function(elem){
196
+ return !!($.prop(elem, 'willValidate') && $.prop(elem, 'required'));
197
+ },
198
+ "user-error": function(elem){
199
+ return ($.prop(elem, 'willValidate') && $(elem).hasClass('user-error'));
200
+ },
201
+ "optional-element": function(elem){
202
+ return !!($.prop(elem, 'willValidate') && $.prop(elem, 'required') === false);
203
+ },
204
+ "in-range": function(elem){
205
+ if(!rangeTypes[$.prop(elem, 'type')] || !$.prop(elem, 'willValidate')){
206
+ return false;
207
+ }
208
+ var val = $.prop(elem, 'validity');
209
+ return !!(val && !val.rangeOverflow && !val.rangeUnderflow);
210
+ },
211
+ "out-of-range": function(elem){
212
+ if(!rangeTypes[$.prop(elem, 'type')] || !$.prop(elem, 'willValidate')){
213
+ return false;
214
+ }
215
+ var val = $.prop(elem, 'validity');
216
+ return !!(val && (val.rangeOverflow || val.rangeUnderflow));
217
+ }
218
+
219
+ });
220
+
221
+ ['valid', 'invalid', 'required', 'optional'].forEach(function(name){
222
+ $.expr[":"][name] = $.expr.filters[name+"-element"];
223
+ });
224
+
225
+
226
+ $.expr[":"].focus = function( elem ) {
227
+ try {
228
+ var doc = elem.ownerDocument;
229
+ return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus());
230
+ } catch(e){}
231
+ return false;
232
+ };
233
+
234
+ if(Modernizr.formvalidation && $.browser.webkit && !webshims.bugs.bustedValidity && webshims.browserVersion < 27){
235
+ (function(){
236
+ var retriggerRadioValidity = function(){
237
+ var validity;
238
+ if((validity = this.validity) && !validity.customError){
239
+ this.setCustomValidity('');
240
+ }
241
+ };
242
+
243
+ webshims.addReady(function(context, insertedElement){
244
+ if(context !== document){
245
+ $('input[type="radio"]:invalid', context)
246
+ .add(insertedElement.filter('input[type="radio"]:invalid'))
247
+ .each(retriggerRadioValidity)
248
+ ;
249
+ }
250
+ });
251
+ })();
252
+ }
253
+
254
+ var customEvents = $.event.customEvent || {};
255
+ var isValid = function(elem){
256
+ return ($.prop(elem, 'validity') || {valid: 1}).valid;
257
+ };
258
+
259
+ if (bugs.bustedValidity || bugs.findRequired) {
260
+ (function(){
261
+ var find = $.find;
262
+ var matchesSelector = $.find.matchesSelector;
263
+
264
+ var regExp = /(\:valid|\:invalid|\:optional|\:required|\:in-range|\:out-of-range)(?=[\s\[\~\.\+\>\:\#*]|$)/ig;
265
+ var regFn = function(sel){
266
+ return sel + '-element';
267
+ };
268
+
269
+ $.find = (function(){
270
+ var slice = Array.prototype.slice;
271
+ var fn = function(sel){
272
+ var ar = arguments;
273
+ ar = slice.call(ar, 1, ar.length);
274
+ ar.unshift(sel.replace(regExp, regFn));
275
+ return find.apply(this, ar);
276
+ };
277
+ for (var i in find) {
278
+ if(find.hasOwnProperty(i)){
279
+ fn[i] = find[i];
280
+ }
281
+ }
282
+ return fn;
283
+ })();
284
+ if(!Modernizr.prefixed || Modernizr.prefixed("matchesSelector", document.documentElement)){
285
+ $.find.matchesSelector = function(node, expr){
286
+ expr = expr.replace(regExp, regFn);
287
+ return matchesSelector.call(this, node, expr);
288
+ };
289
+ }
290
+
291
+ })();
292
+ }
293
+
294
+ //ToDo needs testing
295
+ var oldAttr = $.prop;
296
+ var changeVals = {selectedIndex: 1, value: 1, checked: 1, disabled: 1, readonly: 1};
297
+ $.prop = function(elem, name, val){
298
+ var ret = oldAttr.apply(this, arguments);
299
+ if(elem && 'form' in elem && changeVals[name] && val !== undefined && $(elem).hasClass(invalidClass)){
300
+ if(isValid(elem)){
301
+ $(elem).getShadowElement().removeClass(invalidClasses);
302
+ if(name == 'checked' && val) {
303
+ getGroupElements(elem).not(elem).removeClass(invalidClasses).removeAttr('aria-invalid');
304
+ }
305
+ }
306
+ }
307
+ return ret;
308
+ };
309
+
310
+ var returnValidityCause = function(validity, elem){
311
+ var ret;
312
+ $.each(validity, function(name, value){
313
+ if(value){
314
+ ret = (name == 'customError') ? $.prop(elem, 'validationMessage') : name;
315
+ return false;
316
+ }
317
+ });
318
+ return ret;
319
+ };
320
+
321
+ var isInGroup = function(name){
322
+ var ret;
323
+ try {
324
+ ret = document.activeElement.name === name;
325
+ } catch(e){}
326
+ return ret;
327
+ };
328
+ /* form-ui-invalid/form-ui-valid are deprecated. use user-error/user-success instead */
329
+ var invalidClass = 'user-error';
330
+ var invalidClasses = 'user-error form-ui-invalid';
331
+ var validClass = 'user-success';
332
+ var validClasses = 'user-success form-ui-valid';
333
+ var switchValidityClass = function(e){
334
+ var elem, timer;
335
+ if(!e.target){return;}
336
+ elem = $(e.target).getNativeElement()[0];
337
+ if(elem.type == 'submit' || !$.prop(elem, 'willValidate')){return;}
338
+ timer = $.data(elem, 'webshimsswitchvalidityclass');
339
+ var switchClass = function(){
340
+ if(e.type == 'focusout' && elem.type == 'radio' && isInGroup(elem.name)){return;}
341
+ var validity = $.prop(elem, 'validity');
342
+ var shadowElem = $(elem).getShadowElement();
343
+ var addClass, removeClass, trigger, generaltrigger, validityCause;
344
+
345
+ $(elem).trigger('refreshCustomValidityRules');
346
+ if(validity.valid){
347
+ if(!shadowElem.hasClass(validClass)){
348
+ addClass = validClasses;
349
+ removeClass = invalidClasses;
350
+ generaltrigger = 'changedvaliditystate';
351
+ trigger = 'changedvalid';
352
+ if(checkTypes[elem.type] && elem.checked){
353
+ getGroupElements(elem).not(elem).removeClass(removeClass).addClass(addClass).removeAttr('aria-invalid');
354
+ }
355
+ $.removeData(elem, 'webshimsinvalidcause');
356
+ }
357
+ } else {
358
+ validityCause = returnValidityCause(validity, elem);
359
+ if($.data(elem, 'webshimsinvalidcause') != validityCause){
360
+ $.data(elem, 'webshimsinvalidcause', validityCause);
361
+ generaltrigger = 'changedvaliditystate';
362
+ }
363
+ if(!shadowElem.hasClass(invalidClass)){
364
+ addClass = invalidClasses;
365
+ removeClass = validClasses;
366
+ if (checkTypes[elem.type] && !elem.checked) {
367
+ getGroupElements(elem).not(elem).removeClass(removeClass).addClass(addClass);
368
+ }
369
+ trigger = 'changedinvalid';
370
+ }
371
+ }
372
+ if(addClass){
373
+ shadowElem.addClass(addClass).removeClass(removeClass);
374
+ //jQuery 1.6.1 IE9 bug (doubble trigger bug)
375
+ setTimeout(function(){
376
+ $(elem).trigger(trigger);
377
+ }, 0);
378
+ }
379
+ if(generaltrigger){
380
+ setTimeout(function(){
381
+ $(elem).trigger(generaltrigger);
382
+ }, 0);
383
+ }
384
+ $.removeData(e.target, 'webshimsswitchvalidityclass');
385
+ };
386
+
387
+ if(timer){
388
+ clearTimeout(timer);
389
+ }
390
+ if(e.type == 'refreshvalidityui'){
391
+ switchClass();
392
+ } else {
393
+ $.data(elem, 'webshimsswitchvalidityclass', setTimeout(switchClass, 9));
394
+ }
395
+ };
396
+
397
+ $(document).on(options.validityUIEvents || 'focusout change refreshvalidityui', switchValidityClass);
398
+ customEvents.changedvaliditystate = true;
399
+ customEvents.refreshCustomValidityRules = true;
400
+ customEvents.changedvalid = true;
401
+ customEvents.changedinvalid = true;
402
+ customEvents.refreshvalidityui = true;
403
+
404
+
405
+ webshims.triggerInlineForm = function(elem, event){
406
+ $(elem).trigger(event);
407
+ };
408
+
409
+ webshims.modules["form-core"].getGroupElements = getGroupElements;
410
+
411
+
412
+ var setRoot = function(){
413
+ webshims.scrollRoot = ($.browser.webkit || document.compatMode == 'BackCompat') ?
414
+ $(document.body) :
415
+ $(document.documentElement)
416
+ ;
417
+ };
418
+ setRoot();
419
+ webshims.ready('DOM', setRoot);
420
+
421
+ webshims.getRelOffset = function(posElem, relElem){
422
+ posElem = $(posElem);
423
+ var offset = $(relElem).offset();
424
+ var bodyOffset;
425
+ $.swap($(posElem)[0], {visibility: 'hidden', display: 'inline-block', left: 0, top: 0}, function(){
426
+ bodyOffset = posElem.offset();
427
+ });
428
+ offset.top -= bodyOffset.top;
429
+ offset.left -= bodyOffset.left;
430
+ return offset;
431
+ };
432
+
433
+ /* some extra validation UI */
434
+ webshims.validityAlert = (function(){
435
+ var alertElem = (!$.browser.msie || parseInt($.browser.version, 10) > 7) ? 'span' : 'label';
436
+ var errorBubble;
437
+ var hideTimer = false;
438
+ var focusTimer = false;
439
+ var resizeTimer = false;
440
+ var boundHide;
441
+
442
+ var api = {
443
+ hideDelay: 5000,
444
+
445
+ showFor: function(elem, message, noFocusElem, noBubble){
446
+ api._create();
447
+ elem = $(elem);
448
+ var visual = $(elem).getShadowElement();
449
+ var offset = api.getOffsetFromBody(visual);
450
+ api.clear();
451
+ if(noBubble){
452
+ this.hide();
453
+ } else {
454
+
455
+ this.getMessage(elem, message);
456
+ this.position(visual, offset);
457
+
458
+ this.show();
459
+ if(this.hideDelay){
460
+ hideTimer = setTimeout(boundHide, this.hideDelay);
461
+ }
462
+ $(window)
463
+ .on('resize.validityalert reposoverlay.validityalert', function(){
464
+ clearTimeout(resizeTimer);
465
+ resizeTimer = setTimeout(function(){
466
+ api.position(visual);
467
+ }, 9);
468
+ })
469
+ ;
470
+ }
471
+
472
+ if(!noFocusElem){
473
+ this.setFocus(visual, offset);
474
+ }
475
+ },
476
+ getOffsetFromBody: function(elem){
477
+ return webshims.getRelOffset(errorBubble, elem);
478
+ },
479
+ setFocus: function(visual, offset){
480
+ var focusElem = $(visual).getShadowFocusElement();
481
+ var scrollTop = webshims.scrollRoot.scrollTop();
482
+ var elemTop = ((offset || focusElem.offset()).top) - 30;
483
+ var smooth;
484
+
485
+ if(webshims.getID && alertElem == 'label'){
486
+ errorBubble.attr('for', webshims.getID(focusElem));
487
+ }
488
+
489
+ if(scrollTop > elemTop){
490
+ webshims.scrollRoot.animate(
491
+ {scrollTop: elemTop - 5},
492
+ {
493
+ queue: false,
494
+ duration: Math.max( Math.min( 600, (scrollTop - elemTop) * 1.5 ), 80 )
495
+ }
496
+ );
497
+ smooth = true;
498
+ }
499
+ try {
500
+ focusElem[0].focus();
501
+ } catch(e){}
502
+ if(smooth){
503
+ webshims.scrollRoot.scrollTop(scrollTop);
504
+ setTimeout(function(){
505
+ webshims.scrollRoot.scrollTop(scrollTop);
506
+ }, 0);
507
+ }
508
+ setTimeout(function(){
509
+ $(document).on('focusout.validityalert', boundHide);
510
+ }, 10);
511
+ $(window).triggerHandler('reposoverlay');
512
+ },
513
+ getMessage: function(elem, message){
514
+ if (!message) {
515
+ message = getContentValidationMessage(elem[0]) || elem.prop('customValidationMessage') || elem.prop('validationMessage');
516
+ }
517
+ if (message) {
518
+ $('span.va-box', errorBubble).text(message);
519
+ }
520
+ else {
521
+ this.hide();
522
+ }
523
+ },
524
+ position: function(elem, offset){
525
+ offset = offset ? $.extend({}, offset) : api.getOffsetFromBody(elem);
526
+ offset.top += elem.outerHeight();
527
+ errorBubble.css(offset);
528
+ },
529
+ show: function(){
530
+ if(errorBubble.css('display') === 'none'){
531
+ errorBubble.css({opacity: 0}).show();
532
+ }
533
+ errorBubble.addClass('va-visible').fadeTo(400, 1);
534
+ },
535
+ hide: function(){
536
+ errorBubble.removeClass('va-visible').fadeOut();
537
+ },
538
+ clear: function(){
539
+ clearTimeout(focusTimer);
540
+ clearTimeout(hideTimer);
541
+ $(document).unbind('.validityalert');
542
+ $(window).unbind('.validityalert');
543
+ errorBubble.stop().removeAttr('for');
544
+ },
545
+ _create: function(){
546
+ if(errorBubble){return;}
547
+ errorBubble = api.errorBubble = $('<'+alertElem+' class="validity-alert-wrapper" role="alert"><span class="validity-alert"><span class="va-arrow"><span class="va-arrow-box"></span></span><span class="va-box"></span></span></'+alertElem+'>').css({position: 'absolute', display: 'none'});
548
+ webshims.ready('DOM', function(){
549
+ errorBubble.appendTo('body');
550
+ if($.fn.bgIframe && $.browser.msie && parseInt($.browser.version, 10) < 7){
551
+ errorBubble.bgIframe();
552
+ }
553
+ });
554
+ }
555
+ };
556
+
557
+
558
+ boundHide = $.proxy(api, 'hide');
559
+
560
+ return api;
561
+ })();
562
+
563
+
564
+ /* extension, but also used to fix native implementation workaround/bugfixes */
565
+ (function(){
566
+ var firstEvent,
567
+ invalids = [],
568
+ stopSubmitTimer,
569
+ form
570
+ ;
571
+
572
+ $(document).on('invalid', function(e){
573
+ if(e.wrongWebkitInvalid){return;}
574
+ var jElm = $(e.target);
575
+ var shadowElem = jElm.getShadowElement();
576
+ if(!shadowElem.hasClass(invalidClass)){
577
+ shadowElem.addClass(invalidClasses).removeClass(validClasses);
578
+ setTimeout(function(){
579
+ $(e.target).trigger('changedinvalid').trigger('changedvaliditystate');
580
+ }, 0);
581
+ }
582
+
583
+ if(!firstEvent){
584
+ //trigger firstinvalid
585
+ firstEvent = $.Event('firstinvalid');
586
+ firstEvent.isInvalidUIPrevented = e.isDefaultPrevented;
587
+ var firstSystemInvalid = $.Event('firstinvalidsystem');
588
+ $(document).triggerHandler(firstSystemInvalid, {element: e.target, form: e.target.form, isInvalidUIPrevented: e.isDefaultPrevented});
589
+ jElm.trigger(firstEvent);
590
+ }
591
+
592
+ //if firstinvalid was prevented all invalids will be also prevented
593
+ if( firstEvent && firstEvent.isDefaultPrevented() ){
594
+ e.preventDefault();
595
+ }
596
+ invalids.push(e.target);
597
+ e.extraData = 'fix';
598
+ clearTimeout(stopSubmitTimer);
599
+ stopSubmitTimer = setTimeout(function(){
600
+ var lastEvent = {type: 'lastinvalid', cancelable: false, invalidlist: $(invalids)};
601
+ //reset firstinvalid
602
+ firstEvent = false;
603
+ invalids = [];
604
+ $(e.target).trigger(lastEvent, lastEvent);
605
+ }, 9);
606
+ jElm = null;
607
+ shadowElem = null;
608
+ });
609
+ })();
610
+
611
+ $.fn.getErrorMessage = function(){
612
+ var message = '';
613
+ var elem = this[0];
614
+ if(elem){
615
+ message = getContentValidationMessage(elem) || $.prop(elem, 'customValidationMessage') || $.prop(elem, 'validationMessage');
616
+ }
617
+ return message;
618
+ };
619
+
620
+ if(options.replaceValidationUI){
621
+ webshims.ready('DOM forms', function(){
622
+ $(document).on('firstinvalid', function(e){
623
+ if(!e.isInvalidUIPrevented()){
624
+ e.preventDefault();
625
+ $.webshims.validityAlert.showFor( e.target );
626
+ }
627
+ });
628
+ });
629
+ }
630
+
631
+ });
632
+ jQuery.webshims.register('form-native-extend', function($, webshims, window, doc, undefined, options){
633
+ "use strict";
634
+ var Modernizr = window.Modernizr;
635
+ var modernizrInputTypes = Modernizr.inputtypes;
636
+ if(!Modernizr.formvalidation || webshims.bugs.bustedValidity){return;}
637
+ var typeModels = webshims.inputTypes;
638
+ var validityRules = {};
639
+
640
+ webshims.addInputType = function(type, obj){
641
+ typeModels[type] = obj;
642
+ };
643
+
644
+ webshims.addValidityRule = function(type, fn){
645
+ validityRules[type] = fn;
646
+ };
647
+
648
+ webshims.addValidityRule('typeMismatch',function (input, val, cache, validityState){
649
+ if(val === ''){return false;}
650
+ var ret = validityState.typeMismatch;
651
+ if(!('type' in cache)){
652
+ cache.type = (input[0].getAttribute('type') || '').toLowerCase();
653
+ }
654
+
655
+ if(typeModels[cache.type] && typeModels[cache.type].mismatch){
656
+ ret = typeModels[cache.type].mismatch(val, input);
657
+ }
658
+ return ret;
659
+ });
660
+
661
+ var overrideNativeMessages = options.overrideMessages;
662
+
663
+ var overrideValidity = (!modernizrInputTypes.number || !modernizrInputTypes.time || !modernizrInputTypes.range || overrideNativeMessages);
664
+ var validityProps = ['customError','typeMismatch','rangeUnderflow','rangeOverflow','stepMismatch','tooLong','patternMismatch','valueMissing','valid'];
665
+
666
+ var validityChanger = (overrideNativeMessages)? ['value', 'checked'] : ['value'];
667
+ var validityElements = [];
668
+ var testValidity = function(elem, init){
669
+ if(!elem){return;}
670
+ var type = (elem.getAttribute && elem.getAttribute('type') || elem.type || '').toLowerCase();
671
+
672
+ if(!overrideNativeMessages && !typeModels[type]){
673
+ return;
674
+ }
675
+
676
+ if(overrideNativeMessages && !init && type == 'radio' && elem.name){
677
+ $(doc.getElementsByName( elem.name )).each(function(){
678
+ $.prop(this, 'validity');
679
+ });
680
+ } else {
681
+ $.prop(elem, 'validity');
682
+ }
683
+ };
684
+
685
+ var oldSetCustomValidity = {};
686
+ ['input', 'textarea', 'select'].forEach(function(name){
687
+ var desc = webshims.defineNodeNameProperty(name, 'setCustomValidity', {
688
+ prop: {
689
+ value: function(error){
690
+ error = error+'';
691
+ var elem = (name == 'input') ? $(this).getNativeElement()[0] : this;
692
+ desc.prop._supvalue.call(elem, error);
693
+
694
+ if(webshims.bugs.validationMessage){
695
+ webshims.data(elem, 'customvalidationMessage', error);
696
+ }
697
+ if(overrideValidity){
698
+ webshims.data(elem, 'hasCustomError', !!(error));
699
+ testValidity(elem);
700
+ }
701
+ }
702
+ }
703
+ });
704
+ oldSetCustomValidity[name] = desc.prop._supvalue;
705
+ });
706
+
707
+
708
+ if(overrideValidity || overrideNativeMessages){
709
+ validityChanger.push('min');
710
+ validityChanger.push('max');
711
+ validityChanger.push('step');
712
+ validityElements.push('input');
713
+ }
714
+ if(overrideNativeMessages){
715
+ validityChanger.push('required');
716
+ validityChanger.push('pattern');
717
+ validityElements.push('select');
718
+ validityElements.push('textarea');
719
+ }
720
+
721
+ if(overrideValidity){
722
+ var stopValidity;
723
+ validityElements.forEach(function(nodeName){
724
+
725
+ var oldDesc = webshims.defineNodeNameProperty(nodeName, 'validity', {
726
+ prop: {
727
+ get: function(){
728
+ if(stopValidity){return;}
729
+ var elem = (nodeName == 'input') ? $(this).getNativeElement()[0] : this;
730
+
731
+ var validity = oldDesc.prop._supget.call(elem);
732
+
733
+ if(!validity){
734
+ return validity;
735
+ }
736
+ var validityState = {};
737
+ validityProps.forEach(function(prop){
738
+ validityState[prop] = validity[prop];
739
+ });
740
+
741
+ if( !$.prop(elem, 'willValidate') ){
742
+ return validityState;
743
+ }
744
+ stopValidity = true;
745
+ var jElm = $(elem),
746
+ cache = {type: (elem.getAttribute && elem.getAttribute('type') || '').toLowerCase(), nodeName: (elem.nodeName || '').toLowerCase()},
747
+ val = jElm.val(),
748
+ customError = !!(webshims.data(elem, 'hasCustomError')),
749
+ setCustomMessage
750
+ ;
751
+ stopValidity = false;
752
+ validityState.customError = customError;
753
+
754
+ if( validityState.valid && validityState.customError ){
755
+ validityState.valid = false;
756
+ } else if(!validityState.valid) {
757
+ var allFalse = true;
758
+ $.each(validityState, function(name, prop){
759
+ if(prop){
760
+ allFalse = false;
761
+ return false;
762
+ }
763
+ });
764
+
765
+ if(allFalse){
766
+ validityState.valid = true;
767
+ }
768
+
769
+ }
770
+
771
+ $.each(validityRules, function(rule, fn){
772
+ validityState[rule] = fn(jElm, val, cache, validityState);
773
+ if( validityState[rule] && (validityState.valid || !setCustomMessage) && (overrideNativeMessages || (typeModels[cache.type] && typeModels[cache.type].mismatch)) ) {
774
+ oldSetCustomValidity[nodeName].call(elem, webshims.createValidationMessage(elem, rule));
775
+ validityState.valid = false;
776
+ setCustomMessage = true;
777
+ }
778
+ });
779
+ if(validityState.valid){
780
+ oldSetCustomValidity[nodeName].call(elem, '');
781
+ webshims.data(elem, 'hasCustomError', false);
782
+ } else if(overrideNativeMessages && !setCustomMessage && !customError){
783
+ $.each(validityState, function(name, prop){
784
+ if(name !== 'valid' && prop){
785
+ oldSetCustomValidity[nodeName].call(elem, webshims.createValidationMessage(elem, name));
786
+ return false;
787
+ }
788
+ });
789
+ }
790
+ return validityState;
791
+ },
792
+ writeable: false
793
+
794
+ }
795
+ });
796
+ });
797
+
798
+ validityChanger.forEach(function(prop){
799
+ webshims.onNodeNamesPropertyModify(validityElements, prop, function(s){
800
+ testValidity(this);
801
+ });
802
+ });
803
+
804
+ if(doc.addEventListener){
805
+ var inputThrottle;
806
+ var testPassValidity = function(e){
807
+ if(!('form' in e.target)){return;}
808
+ var form = e.target.form;
809
+ clearTimeout(inputThrottle);
810
+ testValidity(e.target);
811
+ if(form && overrideNativeMessages){
812
+ $('input', form).each(function(){
813
+ if(this.type == 'password'){
814
+ testValidity(this);
815
+ }
816
+ });
817
+ }
818
+ };
819
+
820
+ doc.addEventListener('change', testPassValidity, true);
821
+
822
+ if(overrideNativeMessages){
823
+ doc.addEventListener('blur', testPassValidity, true);
824
+ doc.addEventListener('keydown', function(e){
825
+ if(e.keyCode != 13){return;}
826
+ testPassValidity(e);
827
+ }, true);
828
+ }
829
+
830
+ doc.addEventListener('input', function(e){
831
+ clearTimeout(inputThrottle);
832
+ inputThrottle = setTimeout(function(){
833
+ testValidity(e.target);
834
+ }, 290);
835
+ }, true);
836
+ }
837
+
838
+ var validityElementsSel = validityElements.join(',');
839
+
840
+ webshims.addReady(function(context, elem){
841
+ $(validityElementsSel, context).add(elem.filter(validityElementsSel)).each(function(){
842
+ $.prop(this, 'validity');
843
+ });
844
+ });
845
+
846
+
847
+ if(overrideNativeMessages){
848
+ webshims.ready('DOM form-message', function(){
849
+ webshims.activeLang({
850
+ register: 'form-core',
851
+ callback: function(){
852
+ $('input, select, textarea')
853
+ .getNativeElement()
854
+ .each(function(){
855
+ if(webshims.data(this, 'hasCustomError')){return;}
856
+ var elem = this;
857
+ var validity = $.prop(elem, 'validity') || {valid: true};
858
+ var nodeName;
859
+ if(validity.valid){return;}
860
+ nodeName = (elem.nodeName || '').toLowerCase();
861
+ $.each(validity, function(name, prop){
862
+ if(name !== 'valid' && prop){
863
+ oldSetCustomValidity[nodeName].call(elem, webshims.createValidationMessage(elem, name));
864
+ return false;
865
+ }
866
+ });
867
+ })
868
+ ;
869
+ }
870
+ });
871
+ });
872
+ }
873
+
874
+ } //end: overrideValidity
875
+
876
+ webshims.defineNodeNameProperty('input', 'type', {
877
+ prop: {
878
+ get: function(){
879
+ var elem = this;
880
+ var type = (elem.getAttribute('type') || '').toLowerCase();
881
+ return (webshims.inputTypes[type]) ? type : elem.type;
882
+ }
883
+ }
884
+ });
885
+
886
+
887
+ });
888
+ jQuery.webshims.register('form-message', function($, webshims, window, document, undefined, options){
889
+ "use strict";
890
+ var validityMessages = webshims.validityMessages;
891
+
892
+ var implementProperties = (options.overrideMessages || options.customMessages) ? ['customValidationMessage'] : [];
893
+
894
+ validityMessages['en'] = $.extend(true, {
895
+ typeMismatch: {
896
+ email: 'Please enter an email address.',
897
+ url: 'Please enter a URL.',
898
+ number: 'Please enter a number.',
899
+ date: 'Please enter a date.',
900
+ time: 'Please enter a time.',
901
+ range: 'Invalid input.',
902
+ "datetime-local": 'Please enter a datetime.'
903
+ },
904
+ rangeUnderflow: {
905
+ defaultMessage: 'Value must be greater than or equal to {%min}.'
906
+ },
907
+ rangeOverflow: {
908
+ defaultMessage: 'Value must be less than or equal to {%max}.'
909
+ },
910
+ stepMismatch: 'Invalid input.',
911
+ tooLong: 'Please enter at most {%maxlength} character(s). You entered {%valueLen}.',
912
+
913
+ patternMismatch: 'Invalid input. {%title}',
914
+ valueMissing: {
915
+ defaultMessage: 'Please fill out this field.',
916
+ checkbox: 'Please check this box if you want to proceed.'
917
+ }
918
+ }, (validityMessages['en'] || validityMessages['en-US'] || {}));
919
+
920
+
921
+ ['select', 'radio'].forEach(function(type){
922
+ if(typeof validityMessages['en'].valueMissing == 'object'){
923
+ validityMessages['en'].valueMissing[type] = 'Please select an option.';
924
+ }
925
+ });
926
+
927
+ ['date', 'time', 'datetime-local'].forEach(function(type){
928
+ if(typeof validityMessages['en'].rangeUnderflow == 'object'){
929
+ validityMessages.en.rangeUnderflow[type] = 'Value must be at or after {%min}.';
930
+ }
931
+ });
932
+ ['date', 'time', 'datetime-local'].forEach(function(type){
933
+ if(typeof validityMessages['en'].rangeOverflow == 'object'){
934
+ validityMessages.en.rangeOverflow[type] = 'Value must be at or before {%max}.';
935
+ }
936
+ });
937
+
938
+ validityMessages['en-US'] = validityMessages['en-US'] || validityMessages['en'];
939
+ validityMessages[''] = validityMessages[''] || validityMessages['en-US'];
940
+
941
+ validityMessages['de'] = $.extend(true, {
942
+ typeMismatch: {
943
+ email: '{%value} ist keine zulässige E-Mail-Adresse',
944
+ url: '{%value} ist keine zulässige Webadresse',
945
+ number: '{%value} ist keine Nummer!',
946
+ date: '{%value} ist kein Datum',
947
+ time: '{%value} ist keine Uhrzeit',
948
+ range: '{%value} ist keine Nummer!',
949
+ "datetime-local": '{%value} ist kein Datum-Uhrzeit Format.'
950
+ },
951
+ rangeUnderflow: {
952
+ defaultMessage: '{%value} ist zu niedrig. {%min} ist der unterste Wert, den Sie benutzen können.'
953
+ },
954
+ rangeOverflow: {
955
+ defaultMessage: '{%value} ist zu hoch. {%max} ist der oberste Wert, den Sie benutzen können.'
956
+ },
957
+ stepMismatch: 'Der Wert {%value} ist in diesem Feld nicht zulässig. Hier sind nur bestimmte Werte zulässig. {%title}',
958
+ tooLong: 'Der eingegebene Text ist zu lang! Sie haben {%valueLen} Zeichen eingegeben, dabei sind {%maxlength} das Maximum.',
959
+ patternMismatch: '{%value} hat für dieses Eingabefeld ein falsches Format! {%title}',
960
+ valueMissing: {
961
+ defaultMessage: 'Bitte geben Sie einen Wert ein',
962
+ checkbox: 'Bitte aktivieren Sie das Kästchen'
963
+ }
964
+ }, (validityMessages['de'] || {}));
965
+
966
+ ['select', 'radio'].forEach(function(type){
967
+ if(typeof validityMessages['de'].valueMissing == 'object'){
968
+ validityMessages['de'].valueMissing[type] = 'Bitte wählen Sie eine Option aus';
969
+ }
970
+ });
971
+
972
+ ['date', 'time', 'datetime-local'].forEach(function(type){
973
+ if(typeof validityMessages['de'].rangeUnderflow == 'object'){
974
+ validityMessages.de.rangeUnderflow[type] = '{%value} ist zu früh. {%min} ist die früheste Zeit, die Sie benutzen können.';
975
+ }
976
+ });
977
+ ['date', 'time', 'datetime-local'].forEach(function(type){
978
+ if(typeof validityMessages['de'].rangeOverflow == 'object'){
979
+ validityMessages.de.rangeOverflow[type] = '{%value} ist zu spät. {%max} ist die späteste Zeit, die Sie benutzen können.';
980
+ }
981
+ });
982
+
983
+ var currentValidationMessage = validityMessages[''];
984
+
985
+
986
+ webshims.createValidationMessage = function(elem, name){
987
+ var message = currentValidationMessage[name];
988
+ if(message && typeof message !== 'string'){
989
+ message = message[ $.prop(elem, 'type') ] || message[ (elem.nodeName || '').toLowerCase() ] || message[ 'defaultMessage' ];
990
+ }
991
+ if(message){
992
+ ['value', 'min', 'max', 'title', 'maxlength', 'label'].forEach(function(attr){
993
+ if(message.indexOf('{%'+attr) === -1){return;}
994
+ var val = ((attr == 'label') ? $.trim($('label[for="'+ elem.id +'"]', elem.form).text()).replace(/\*$|:$/, '') : $.attr(elem, attr)) || '';
995
+ if(name == 'patternMismatch' && attr == 'title' && !val){
996
+ webshims.error('no title for patternMismatch provided. Always add a title attribute.');
997
+ }
998
+ message = message.replace('{%'+ attr +'}', val);
999
+ if('value' == attr){
1000
+ message = message.replace('{%valueLen}', val.length);
1001
+ }
1002
+ });
1003
+ }
1004
+ return message || '';
1005
+ };
1006
+
1007
+
1008
+ if(webshims.bugs.validationMessage || !Modernizr.formvalidation || webshims.bugs.bustedValidity){
1009
+ implementProperties.push('validationMessage');
1010
+ }
1011
+
1012
+ webshims.activeLang({
1013
+ langObj: validityMessages,
1014
+ module: 'form-core',
1015
+ callback: function(langObj){
1016
+ currentValidationMessage = langObj;
1017
+ }
1018
+ });
1019
+
1020
+ implementProperties.forEach(function(messageProp){
1021
+ webshims.defineNodeNamesProperty(['fieldset', 'output', 'button'], messageProp, {
1022
+ prop: {
1023
+ value: '',
1024
+ writeable: false
1025
+ }
1026
+ });
1027
+ ['input', 'select', 'textarea'].forEach(function(nodeName){
1028
+ var desc = webshims.defineNodeNameProperty(nodeName, messageProp, {
1029
+ prop: {
1030
+ get: function(){
1031
+ var elem = this;
1032
+ var message = '';
1033
+ if(!$.prop(elem, 'willValidate')){
1034
+ return message;
1035
+ }
1036
+
1037
+ var validity = $.prop(elem, 'validity') || {valid: 1};
1038
+
1039
+ if(validity.valid){return message;}
1040
+ message = webshims.getContentValidationMessage(elem, validity);
1041
+
1042
+ if(message){return message;}
1043
+
1044
+ if(validity.customError && elem.nodeName){
1045
+ message = (Modernizr.formvalidation && !webshims.bugs.bustedValidity && desc.prop._supget) ? desc.prop._supget.call(elem) : webshims.data(elem, 'customvalidationMessage');
1046
+ if(message){return message;}
1047
+ }
1048
+ $.each(validity, function(name, prop){
1049
+ if(name == 'valid' || !prop){return;}
1050
+
1051
+ message = webshims.createValidationMessage(elem, name);
1052
+ if(message){
1053
+ return false;
1054
+ }
1055
+ });
1056
+ return message || '';
1057
+ },
1058
+ writeable: false
1059
+ }
1060
+ });
1061
+ });
1062
+
1063
+ });
1064
+ });
1065
+ jQuery.webshims.register('form-datalist', function($, webshims, window, document, undefined){
1066
+ "use strict";
1067
+ var doc = document;
1068
+
1069
+ /*
1070
+ * implement propType "element" currently only used for list-attribute (will be moved to dom-extend, if needed)
1071
+ */
1072
+ webshims.propTypes.element = function(descs){
1073
+ webshims.createPropDefault(descs, 'attr');
1074
+ if(descs.prop){return;}
1075
+ descs.prop = {
1076
+ get: function(){
1077
+ var elem = descs.attr.get.call(this);
1078
+ if(elem){
1079
+ elem = document.getElementById(elem);
1080
+ if(elem && descs.propNodeName && !$.nodeName(elem, descs.propNodeName)){
1081
+ elem = null;
1082
+ }
1083
+ }
1084
+ return elem || null;
1085
+ },
1086
+ writeable: false
1087
+ };
1088
+ };
1089
+
1090
+
1091
+ /*
1092
+ * Implements datalist element and list attribute
1093
+ */
1094
+
1095
+ (function(){
1096
+ var formsCFG = $.webshims.cfg.forms;
1097
+ var listSupport = Modernizr.input.list;
1098
+ if(listSupport && !formsCFG.customDatalist){return;}
1099
+
1100
+ var initializeDatalist = function(){
1101
+
1102
+
1103
+ if(!listSupport){
1104
+ webshims.defineNodeNameProperty('datalist', 'options', {
1105
+ prop: {
1106
+ writeable: false,
1107
+ get: function(){
1108
+ var elem = this;
1109
+ var select = $('select', elem);
1110
+ var options;
1111
+ if(select[0]){
1112
+ options = select[0].options;
1113
+ } else {
1114
+ options = $('option', elem).get();
1115
+ if(options.length){
1116
+ webshims.warn('you should wrap your option-elements for a datalist in a select element to support IE and other old browsers.');
1117
+ }
1118
+ }
1119
+ return options;
1120
+ }
1121
+ }
1122
+ });
1123
+ }
1124
+
1125
+ var inputListProto = {
1126
+ //override autocomplete
1127
+ autocomplete: {
1128
+ attr: {
1129
+ get: function(){
1130
+ var elem = this;
1131
+ var data = $.data(elem, 'datalistWidget');
1132
+ if(data){
1133
+ return data._autocomplete;
1134
+ }
1135
+ return ('autocomplete' in elem) ? elem.autocomplete : elem.getAttribute('autocomplete');
1136
+ },
1137
+ set: function(value){
1138
+ var elem = this;
1139
+ var data = $.data(elem, 'datalistWidget');
1140
+ if(data){
1141
+ data._autocomplete = value;
1142
+ if(value == 'off'){
1143
+ data.hideList();
1144
+ }
1145
+ } else {
1146
+ if('autocomplete' in elem){
1147
+ elem.autocomplete = value;
1148
+ } else {
1149
+ elem.setAttribute('autocomplete', value);
1150
+ }
1151
+ }
1152
+ }
1153
+ }
1154
+ }
1155
+ };
1156
+
1157
+ // if(formsCFG.customDatalist && (!listSupport || !('selectedOption') in $('<input />')[0])){
1158
+ // //currently not supported x-browser (FF4 has not implemented and is not polyfilled )
1159
+ // inputListProto.selectedOption = {
1160
+ // prop: {
1161
+ // writeable: false,
1162
+ // get: function(){
1163
+ // var elem = this;
1164
+ // var list = $.prop(elem, 'list');
1165
+ // var ret = null;
1166
+ // var value, options;
1167
+ // if(!list){return ret;}
1168
+ // value = $.prop(elem, 'value');
1169
+ // if(!value){return ret;}
1170
+ // options = $.prop(list, 'options');
1171
+ // if(!options.length){return ret;}
1172
+ // $.each(options, function(i, option){
1173
+ // if(value == $.prop(option, 'value')){
1174
+ // ret = option;
1175
+ // return false;
1176
+ // }
1177
+ // });
1178
+ // return ret;
1179
+ // }
1180
+ // }
1181
+ // };
1182
+ // }
1183
+
1184
+ if(!listSupport){
1185
+ inputListProto['list'] = {
1186
+ attr: {
1187
+ get: function(){
1188
+ var val = webshims.contentAttr(this, 'list');
1189
+ return (val == null) ? undefined : val;
1190
+ },
1191
+ set: function(value){
1192
+ var elem = this;
1193
+ webshims.contentAttr(elem, 'list', value);
1194
+ webshims.objectCreate(shadowListProto, undefined, {input: elem, id: value, datalist: $.prop(elem, 'list')});
1195
+ }
1196
+ },
1197
+ initAttr: true,
1198
+ reflect: true,
1199
+ propType: 'element',
1200
+ propNodeName: 'datalist'
1201
+ };
1202
+ } else {
1203
+ //options only return options, if option-elements are rooted: but this makes this part of HTML5 less backwards compatible
1204
+ if(!($('<datalist><select><option></option></select></datalist>').prop('options') || []).length ){
1205
+ webshims.defineNodeNameProperty('datalist', 'options', {
1206
+ prop: {
1207
+ writeable: false,
1208
+ get: function(){
1209
+ var options = this.options || [];
1210
+ if(!options.length){
1211
+ var elem = this;
1212
+ var select = $('select', elem);
1213
+ if(select[0] && select[0].options && select[0].options.length){
1214
+ options = select[0].options;
1215
+ }
1216
+ }
1217
+ return options;
1218
+ }
1219
+ }
1220
+ });
1221
+ }
1222
+ inputListProto['list'] = {
1223
+ attr: {
1224
+ get: function(){
1225
+ var val = webshims.contentAttr(this, 'list');
1226
+ if(val != null){
1227
+ this.removeAttribute('list');
1228
+ } else {
1229
+ val = $.data(this, 'datalistListAttr');
1230
+ }
1231
+
1232
+ return (val == null) ? undefined : val;
1233
+ },
1234
+ set: function(value){
1235
+ var elem = this;
1236
+ $.data(elem, 'datalistListAttr', value);
1237
+ webshims.objectCreate(shadowListProto, undefined, {input: elem, id: value, datalist: $.prop(elem, 'list')});
1238
+ }
1239
+ },
1240
+ initAttr: true,
1241
+ reflect: true,
1242
+ propType: 'element',
1243
+ propNodeName: 'datalist'
1244
+ };
1245
+ }
1246
+
1247
+
1248
+ webshims.defineNodeNameProperties('input', inputListProto);
1249
+
1250
+ if($.event.customEvent){
1251
+ $.event.customEvent.updateDatalist = true;
1252
+ $.event.customEvent.updateInput = true;
1253
+ $.event.customEvent.datalistselect = true;
1254
+ }
1255
+ webshims.addReady(function(context, contextElem){
1256
+ contextElem
1257
+ .filter('datalist > select, datalist, datalist > option, datalist > select > option')
1258
+ .closest('datalist')
1259
+ .triggerHandler('updateDatalist')
1260
+ ;
1261
+
1262
+ });
1263
+
1264
+
1265
+ };
1266
+
1267
+
1268
+ /*
1269
+ * ShadowList
1270
+ */
1271
+ var listidIndex = 0;
1272
+
1273
+ var noDatalistSupport = {
1274
+ submit: 1,
1275
+ button: 1,
1276
+ reset: 1,
1277
+ hidden: 1,
1278
+
1279
+ //ToDo
1280
+ range: 1,
1281
+ date: 1
1282
+ };
1283
+ var lteie6 = ($.browser.msie && parseInt($.browser.version, 10) < 7);
1284
+ var globStoredOptions = {};
1285
+ var getStoredOptions = function(name){
1286
+ if(!name){return [];}
1287
+ if(globStoredOptions[name]){
1288
+ return globStoredOptions[name];
1289
+ }
1290
+ var data;
1291
+ try {
1292
+ data = JSON.parse(localStorage.getItem('storedDatalistOptions'+name));
1293
+ } catch(e){}
1294
+ globStoredOptions[name] = data || [];
1295
+ return data || [];
1296
+ };
1297
+ var storeOptions = function(name, val){
1298
+ if(!name){return;}
1299
+ val = val || [];
1300
+ try {
1301
+ localStorage.setItem( 'storedDatalistOptions'+name, JSON.stringify(val) );
1302
+ } catch(e){}
1303
+ };
1304
+
1305
+ var getText = function(elem){
1306
+ return (elem.textContent || elem.innerText || $.text([ elem ]) || '');
1307
+ };
1308
+
1309
+ var shadowListProto = {
1310
+ _create: function(opts){
1311
+
1312
+ if(noDatalistSupport[$.prop(opts.input, 'type')]){return;}
1313
+ var datalist = opts.datalist;
1314
+ var data = $.data(opts.input, 'datalistWidget');
1315
+ if(datalist && data && data.datalist !== datalist){
1316
+ data.datalist = datalist;
1317
+ data.id = opts.id;
1318
+
1319
+ data.shadowList.prop('className', 'datalist-polyfill '+ (data.datalist.className || '') + ' '+ data.datalist.id +'-shadowdom');
1320
+ if(formsCFG.positionDatalist){
1321
+ data.shadowList.insertAfter(opts.input);
1322
+ } else {
1323
+ data.shadowList.appendTo('body');
1324
+ }
1325
+ $(data.datalist)
1326
+ .off('updateDatalist.datalistWidget')
1327
+ .on('updateDatalist.datalistWidget', $.proxy(data, '_resetListCached'))
1328
+ ;
1329
+ data._resetListCached();
1330
+ return;
1331
+ } else if(!datalist){
1332
+ if(data){
1333
+ data.destroy();
1334
+ }
1335
+ return;
1336
+ } else if(data && data.datalist === datalist){
1337
+ return;
1338
+ }
1339
+ listidIndex++;
1340
+ var that = this;
1341
+ this.hideList = $.proxy(that, 'hideList');
1342
+ this.timedHide = function(){
1343
+ clearTimeout(that.hideTimer);
1344
+ that.hideTimer = setTimeout(that.hideList, 9);
1345
+ };
1346
+ this.datalist = datalist;
1347
+ this.id = opts.id;
1348
+ this.hasViewableData = true;
1349
+ this._autocomplete = $.attr(opts.input, 'autocomplete');
1350
+ $.data(opts.input, 'datalistWidget', this);
1351
+ this.shadowList = $('<div class="datalist-polyfill '+ (this.datalist.className || '') + ' '+ this.datalist.id +'-shadowdom' +'" />');
1352
+
1353
+ if(formsCFG.positionDatalist || $(opts.input).hasClass('position-datalist')){
1354
+ this.shadowList.insertAfter(opts.input);
1355
+ } else {
1356
+ this.shadowList.appendTo('body');
1357
+ }
1358
+
1359
+ this.index = -1;
1360
+ this.input = opts.input;
1361
+ this.arrayOptions = [];
1362
+
1363
+ this.shadowList
1364
+ .delegate('li', 'mouseenter.datalistWidget mousedown.datalistWidget click.datalistWidget', function(e){
1365
+ var items = $('li:not(.hidden-item)', that.shadowList);
1366
+ var select = (e.type == 'mousedown' || e.type == 'click');
1367
+ that.markItem(items.index(e.currentTarget), select, items);
1368
+ if(e.type == 'click'){
1369
+ that.hideList();
1370
+ if(formsCFG.customDatalist){
1371
+ $(opts.input).trigger('datalistselect');
1372
+ }
1373
+ }
1374
+ return (e.type != 'mousedown');
1375
+ })
1376
+ .on('focusout', this.timedHide)
1377
+ ;
1378
+
1379
+ opts.input.setAttribute('autocomplete', 'off');
1380
+
1381
+ $(opts.input)
1382
+ .attr({
1383
+ //role: 'combobox',
1384
+ 'aria-haspopup': 'true'
1385
+ })
1386
+ .on({
1387
+ 'input.datalistWidget': function(){
1388
+ if(!that.triggeredByDatalist){
1389
+ that.changedValue = false;
1390
+ that.showHideOptions();
1391
+ }
1392
+ },
1393
+ 'keydown.datalistWidget': function(e){
1394
+ var keyCode = e.keyCode;
1395
+ var activeItem;
1396
+ var items;
1397
+ if(keyCode == 40 && !that.showList()){
1398
+ that.markItem(that.index + 1, true);
1399
+ return false;
1400
+ }
1401
+
1402
+ if(!that.isListVisible){return;}
1403
+
1404
+
1405
+ if(keyCode == 38){
1406
+ that.markItem(that.index - 1, true);
1407
+ return false;
1408
+ }
1409
+ if(!e.shiftKey && (keyCode == 33 || keyCode == 36)){
1410
+ that.markItem(0, true);
1411
+ return false;
1412
+ }
1413
+ if(!e.shiftKey && (keyCode == 34 || keyCode == 35)){
1414
+ items = $('li:not(.hidden-item)', that.shadowList);
1415
+ that.markItem(items.length - 1, true, items);
1416
+ return false;
1417
+ }
1418
+ if(keyCode == 13 || keyCode == 27){
1419
+ if (keyCode == 13){
1420
+ activeItem = $('li.active-item:not(.hidden-item)', that.shadowList);
1421
+ that.changeValue( $('li.active-item:not(.hidden-item)', that.shadowList) );
1422
+ }
1423
+ that.hideList();
1424
+ if(formsCFG.customDatalist && activeItem && activeItem[0]){
1425
+ $(opts.input).trigger('datalistselect');
1426
+ }
1427
+ return false;
1428
+ }
1429
+ },
1430
+ 'focus.datalistWidget': function(){
1431
+ if($(this).hasClass('list-focus')){
1432
+ that.showList();
1433
+ }
1434
+ },
1435
+ 'mousedown.datalistWidget': function(){
1436
+ if($(this).is(':focus')){
1437
+ that.showList();
1438
+ }
1439
+ },
1440
+ 'blur.datalistWidget': this.timedHide
1441
+ })
1442
+ ;
1443
+
1444
+
1445
+ $(this.datalist)
1446
+ .off('updateDatalist.datalistWidget')
1447
+ .on('updateDatalist.datalistWidget', $.proxy(this, '_resetListCached'))
1448
+ ;
1449
+
1450
+ this._resetListCached();
1451
+
1452
+ if(opts.input.form && (opts.input.name || opts.input.id)){
1453
+ $(opts.input.form).on('submit.datalistWidget'+opts.input.id, function(){
1454
+ if(!$(opts.input).hasClass('no-datalist-cache') && that._autocomplete != 'off'){
1455
+ var val = $.prop(opts.input, 'value');
1456
+ var name = (opts.input.name || opts.input.id) + $.prop(opts.input, 'type');
1457
+ if(!that.storedOptions){
1458
+ that.storedOptions = getStoredOptions( name );
1459
+ }
1460
+ if(val && that.storedOptions.indexOf(val) == -1){
1461
+ that.storedOptions.push(val);
1462
+ storeOptions(name, that.storedOptions );
1463
+ }
1464
+ }
1465
+ });
1466
+ }
1467
+ $(window).on('unload.datalist'+this.id+' beforeunload.datalist'+this.id, function(){
1468
+ that.destroy();
1469
+ });
1470
+ },
1471
+ destroy: function(){
1472
+ var autocomplete = $.attr(this.input, 'autocomplete');
1473
+ $(this.input)
1474
+ .off('.datalistWidget')
1475
+ .removeData('datalistWidget')
1476
+ ;
1477
+ this.shadowList.remove();
1478
+ $(document).off('.datalist'+this.id);
1479
+ $(window).off('.datalist'+this.id);
1480
+ if(this.input.form && this.input.id){
1481
+ $(this.input.form).off('submit.datalistWidget'+this.input.id);
1482
+ }
1483
+ this.input.removeAttribute('aria-haspopup');
1484
+ if(autocomplete === undefined){
1485
+ this.input.removeAttribute('autocomplete');
1486
+ } else {
1487
+ $(this.input).attr('autocomplete', autocomplete);
1488
+ }
1489
+ },
1490
+ _resetListCached: function(e){
1491
+ var that = this;
1492
+ var forceShow;
1493
+ this.needsUpdate = true;
1494
+ this.lastUpdatedValue = false;
1495
+ this.lastUnfoundValue = '';
1496
+
1497
+ if(!this.updateTimer){
1498
+ if(window.QUnit || (forceShow = (e && document.activeElement == that.input))){
1499
+ that.updateListOptions(forceShow);
1500
+ } else {
1501
+ webshims.ready('WINDOWLOAD', function(){
1502
+ that.updateTimer = setTimeout(function(){
1503
+ that.updateListOptions();
1504
+ that = null;
1505
+ listidIndex = 1;
1506
+ }, 200 + (100 * listidIndex));
1507
+ });
1508
+ }
1509
+ }
1510
+ },
1511
+ maskHTML: function(str){
1512
+ return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
1513
+ },
1514
+ updateListOptions: function(_forceShow){
1515
+ this.needsUpdate = false;
1516
+ clearTimeout(this.updateTimer);
1517
+ this.updateTimer = false;
1518
+ this.shadowList
1519
+ .css({
1520
+ fontSize: $.css(this.input, 'fontSize'),
1521
+ fontFamily: $.css(this.input, 'fontFamily')
1522
+ })
1523
+ ;
1524
+ this.searchStart = formsCFG.customDatalist && $(this.input).hasClass('search-start');
1525
+
1526
+ var list = [];
1527
+
1528
+ var values = [];
1529
+ var allOptions = [];
1530
+ var rElem, rItem, rOptions, rI, rLen, item;
1531
+ for(rOptions = $.prop(this.datalist, 'options'), rI = 0, rLen = rOptions.length; rI < rLen; rI++){
1532
+ rElem = rOptions[rI];
1533
+ if(rElem.disabled){return;}
1534
+ rItem = {
1535
+ value: $(rElem).val() || '',
1536
+ text: $.trim($.attr(rElem, 'label') || getText(rElem)),
1537
+ className: rElem.className || '',
1538
+ style: $.attr(rElem, 'style') || ''
1539
+ };
1540
+ if(!rItem.text){
1541
+ rItem.text = rItem.value;
1542
+ } else if(rItem.text != rItem.value){
1543
+ rItem.className += ' different-label-value';
1544
+ }
1545
+ values[rI] = rItem.value;
1546
+ allOptions[rI] = rItem;
1547
+ }
1548
+
1549
+ if(!this.storedOptions){
1550
+ this.storedOptions = ($(this.input).hasClass('no-datalist-cache') || this._autocomplete == 'off') ? [] : getStoredOptions((this.input.name || this.input.id) + $.prop(this.input, 'type'));
1551
+ }
1552
+
1553
+ this.storedOptions.forEach(function(val, i){
1554
+ if(values.indexOf(val) == -1){
1555
+ allOptions.push({value: val, text: val, className: 'stored-suggest', style: ''});
1556
+ }
1557
+ });
1558
+
1559
+ for(rI = 0, rLen = allOptions.length; rI < rLen; rI++){
1560
+ item = allOptions[rI];
1561
+ 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>';
1562
+ }
1563
+
1564
+ this.arrayOptions = allOptions;
1565
+ this.shadowList.html('<div class="datalist-outer-box"><div class="datalist-box"><ul role="list">'+ list.join("\n") +'</ul></div></div>');
1566
+
1567
+ if($.fn.bgIframe && lteie6){
1568
+ this.shadowList.bgIframe();
1569
+ }
1570
+
1571
+ if(_forceShow || this.isListVisible){
1572
+ this.showHideOptions();
1573
+ }
1574
+ },
1575
+ showHideOptions: function(_fromShowList){
1576
+ var value = $.prop(this.input, 'value').toLowerCase();
1577
+ //first check prevent infinite loop, second creates simple lazy optimization
1578
+ if(value === this.lastUpdatedValue || (this.lastUnfoundValue && value.indexOf(this.lastUnfoundValue) === 0)){
1579
+ return;
1580
+ }
1581
+
1582
+ this.lastUpdatedValue = value;
1583
+ var found = false;
1584
+ var startSearch = this.searchStart;
1585
+ var lis = $('li', this.shadowList);
1586
+ if(value){
1587
+ this.arrayOptions.forEach(function(item, i){
1588
+ var search;
1589
+ if(!('lowerText' in item)){
1590
+ if(item.text != item.value){
1591
+ item.lowerText = item.value.toLowerCase() + item.text.toLowerCase();
1592
+ } else {
1593
+ item.lowerText = item.text.toLowerCase();
1594
+ }
1595
+ }
1596
+ search = item.lowerText.indexOf(value);
1597
+ search = startSearch ? !search : search !== -1;
1598
+ if(search){
1599
+ $(lis[i]).removeClass('hidden-item');
1600
+ found = true;
1601
+ } else {
1602
+ $(lis[i]).addClass('hidden-item');
1603
+ }
1604
+ });
1605
+ } else if(lis.length) {
1606
+ lis.removeClass('hidden-item');
1607
+ found = true;
1608
+ }
1609
+
1610
+ this.hasViewableData = found;
1611
+ if(!_fromShowList && found){
1612
+ this.showList();
1613
+ }
1614
+ if(!found){
1615
+ this.lastUnfoundValue = value;
1616
+ this.hideList();
1617
+ }
1618
+ },
1619
+ setPos: function(){
1620
+ this.shadowList.css({marginTop: 0, marginLeft: 0, marginRight: 0, marginBottom: 0});
1621
+ var css = (formsCFG.positionDatalist) ? $(this.input).position() : webshims.getRelOffset(this.shadowList, this.input);
1622
+ css.top += $(this.input).outerHeight();
1623
+ css.width = $(this.input).outerWidth() - (parseInt(this.shadowList.css('borderLeftWidth'), 10) || 0) - (parseInt(this.shadowList.css('borderRightWidth'), 10) || 0);
1624
+ this.shadowList.css({marginTop: '', marginLeft: '', marginRight: '', marginBottom: ''}).css(css);
1625
+ return css;
1626
+ },
1627
+ showList: function(){
1628
+ if(this.isListVisible){return false;}
1629
+ if(this.needsUpdate){
1630
+ this.updateListOptions();
1631
+ }
1632
+ this.showHideOptions(true);
1633
+ if(!this.hasViewableData){return false;}
1634
+ this.isListVisible = true;
1635
+ var that = this;
1636
+
1637
+ that.setPos();
1638
+ that.shadowList.addClass('datalist-visible').find('li.active-item').removeClass('active-item');
1639
+
1640
+ $(window).unbind('.datalist'+that.id);
1641
+ $(document)
1642
+ .off('.datalist'+that.id)
1643
+ .on('mousedown.datalist'+that.id +' focusin.datalist'+that.id, function(e){
1644
+ if(e.target === that.input || that.shadowList[0] === e.target || $.contains( that.shadowList[0], e.target )){
1645
+ clearTimeout(that.hideTimer);
1646
+ setTimeout(function(){
1647
+ clearTimeout(that.hideTimer);
1648
+ }, 9);
1649
+ } else {
1650
+ that.timedHide();
1651
+ }
1652
+ })
1653
+ .on('updateshadowdom.datalist'+that.id, function(){
1654
+ that.setPos();
1655
+ })
1656
+ ;
1657
+ return true;
1658
+ },
1659
+ hideList: function(){
1660
+ if(!this.isListVisible){return false;}
1661
+ var that = this;
1662
+ var triggerChange = function(e){
1663
+ if(that.changedValue){
1664
+ $(that.input).trigger('change');
1665
+ }
1666
+ that.changedValue = false;
1667
+ };
1668
+
1669
+ that.shadowList.removeClass('datalist-visible list-item-active');
1670
+ that.index = -1;
1671
+ that.isListVisible = false;
1672
+ if(that.changedValue){
1673
+ that.triggeredByDatalist = true;
1674
+ webshims.triggerInlineForm && webshims.triggerInlineForm(that.input, 'input');
1675
+ if($(that.input).is(':focus')){
1676
+ $(that.input).one('blur', triggerChange);
1677
+ } else {
1678
+ triggerChange();
1679
+ }
1680
+ that.triggeredByDatalist = false;
1681
+ }
1682
+ $(document).unbind('.datalist'+that.id);
1683
+ $(window)
1684
+ .off('.datalist'+that.id)
1685
+ .one('resize.datalist'+that.id, function(){
1686
+ that.shadowList.css({top: 0, left: 0});
1687
+ })
1688
+ ;
1689
+ return true;
1690
+ },
1691
+ scrollIntoView: function(elem){
1692
+ var ul = $('ul', this.shadowList);
1693
+ var div = $('div.datalist-box', this.shadowList);
1694
+ var elemPos = elem.position();
1695
+ var containerHeight;
1696
+ elemPos.top -= (parseInt(ul.css('paddingTop'), 10) || 0) + (parseInt(ul.css('marginTop'), 10) || 0) + (parseInt(ul.css('borderTopWidth'), 10) || 0);
1697
+ if(elemPos.top < 0){
1698
+ div.scrollTop( div.scrollTop() + elemPos.top - 2);
1699
+ return;
1700
+ }
1701
+ elemPos.top += elem.outerHeight();
1702
+ containerHeight = div.height();
1703
+ if(elemPos.top > containerHeight){
1704
+ div.scrollTop( div.scrollTop() + (elemPos.top - containerHeight) + 2);
1705
+ }
1706
+ },
1707
+ changeValue: function(activeItem){
1708
+ if(!activeItem[0]){return;}
1709
+ var newValue = $('span.option-value', activeItem).text();
1710
+ var oldValue = $.prop(this.input, 'value');
1711
+ if(newValue != oldValue){
1712
+ $(this.input)
1713
+ .prop('value', newValue)
1714
+ .triggerHandler('updateInput')
1715
+ ;
1716
+ this.changedValue = true;
1717
+ }
1718
+ },
1719
+ markItem: function(index, doValue, items){
1720
+ var activeItem;
1721
+ var goesUp;
1722
+
1723
+ items = items || $('li:not(.hidden-item)', this.shadowList);
1724
+ if(!items.length){return;}
1725
+ if(index < 0){
1726
+ index = items.length - 1;
1727
+ } else if(index >= items.length){
1728
+ index = 0;
1729
+ }
1730
+ items.removeClass('active-item');
1731
+ this.shadowList.addClass('list-item-active');
1732
+ activeItem = items.filter(':eq('+ index +')').addClass('active-item');
1733
+
1734
+ if(doValue){
1735
+ this.changeValue(activeItem);
1736
+ this.scrollIntoView(activeItem);
1737
+ }
1738
+ this.index = index;
1739
+ }
1740
+ };
1741
+
1742
+ //init datalist update
1743
+ initializeDatalist();
1744
+ })();
1745
+
1710
1746
  });