webshims-rails 1.11.1 → 1.11.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +8 -8
  2. data/lib/webshims-rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/webshims/polyfiller.js +41 -20
  4. data/vendor/assets/javascripts/webshims/shims/combos/10.js +212 -42
  5. data/vendor/assets/javascripts/webshims/shims/combos/11.js +196 -37
  6. data/vendor/assets/javascripts/webshims/shims/combos/12.js +82 -36
  7. data/vendor/assets/javascripts/webshims/shims/combos/13.js +82 -36
  8. data/vendor/assets/javascripts/webshims/shims/combos/14.js +17 -6
  9. data/vendor/assets/javascripts/webshims/shims/combos/15.js +234 -1247
  10. data/vendor/assets/javascripts/webshims/shims/combos/16.js +234 -1247
  11. data/vendor/assets/javascripts/webshims/shims/combos/17.js +202 -45
  12. data/vendor/assets/javascripts/webshims/shims/combos/18.js +202 -45
  13. data/vendor/assets/javascripts/webshims/shims/combos/19.js +16 -5
  14. data/vendor/assets/javascripts/webshims/shims/combos/2.js +51 -11
  15. data/vendor/assets/javascripts/webshims/shims/combos/20.js +16 -5
  16. data/vendor/assets/javascripts/webshims/shims/combos/21.js +82 -36
  17. data/vendor/assets/javascripts/webshims/shims/combos/22.js +82 -36
  18. data/vendor/assets/javascripts/webshims/shims/combos/24.js +1689 -997
  19. data/vendor/assets/javascripts/webshims/shims/combos/25.js +16 -5
  20. data/vendor/assets/javascripts/webshims/shims/combos/26.js +16 -5
  21. data/vendor/assets/javascripts/webshims/shims/combos/3.js +16 -5
  22. data/vendor/assets/javascripts/webshims/shims/combos/30.js +51 -11
  23. data/vendor/assets/javascripts/webshims/shims/combos/31.js +51 -11
  24. data/vendor/assets/javascripts/webshims/shims/combos/4.js +16 -5
  25. data/vendor/assets/javascripts/webshims/shims/combos/5.js +202 -45
  26. data/vendor/assets/javascripts/webshims/shims/combos/6.js +237 -51
  27. data/vendor/assets/javascripts/webshims/shims/combos/7.js +51 -11
  28. data/vendor/assets/javascripts/webshims/shims/combos/8.js +16 -5
  29. data/vendor/assets/javascripts/webshims/shims/combos/9.js +247 -48
  30. data/vendor/assets/javascripts/webshims/shims/dom-extend.js +17 -5
  31. data/vendor/assets/javascripts/webshims/shims/form-datalist-lazy.js +21 -3
  32. data/vendor/assets/javascripts/webshims/shims/form-datalist.js +35 -6
  33. data/vendor/assets/javascripts/webshims/shims/form-number-date-api.js +6 -8
  34. data/vendor/assets/javascripts/webshims/shims/form-number-date-ui.js +134 -24
  35. data/vendor/assets/javascripts/webshims/shims/form-shim-extend.js +152 -1205
  36. data/vendor/assets/javascripts/webshims/shims/form-shim-extend2.js +1076 -0
  37. data/vendor/assets/javascripts/webshims/shims/form-validation.js +47 -20
  38. data/vendor/assets/javascripts/webshims/shims/form-validators.js +2 -2
  39. data/vendor/assets/javascripts/webshims/shims/forms-picker.js +1 -1
  40. data/vendor/assets/javascripts/webshims/shims/i18n/{formcfg-de.txt → formcfg-de.js} +3 -0
  41. data/vendor/assets/javascripts/webshims/shims/i18n/{formcfg-en.txt → formcfg-en.js} +5 -1
  42. data/vendor/assets/javascripts/webshims/shims/json-storage.js +1 -1
  43. data/vendor/assets/javascripts/webshims/shims/mediaelement-yt.js +1 -1
  44. data/vendor/assets/javascripts/webshims/shims/range-ui.js +62 -13
  45. data/vendor/assets/javascripts/webshims/shims/styles/forms-ext.css +610 -0
  46. data/vendor/assets/javascripts/webshims/shims/styles/scss/_extends.scss +10 -0
  47. data/vendor/assets/javascripts/webshims/shims/styles/scss/forms-ext.scss +743 -0
  48. data/vendor/assets/javascripts/webshims/shims/styles/scss/shim.scss +1 -755
  49. data/vendor/assets/javascripts/webshims/shims/styles/shim.css +0 -606
  50. data/vendor/assets/javascripts/webshims/shims/swf/JarisFLVPlayer.swf +0 -0
  51. data/vendor/assets/javascripts/webshims/shims/track-ui.js +36 -23
  52. data/vendor/assets/javascripts/webshims/shims/track.js +82 -36
  53. metadata +8 -6
  54. data/vendor/assets/javascripts/webshims/shims/combos/28.js +0 -2196
  55. data/vendor/assets/javascripts/webshims/shims/combos/29.js +0 -1167
@@ -205,8 +205,8 @@ webshims.register('track', function($, webshims, window, document, undefined){
205
205
  kind: 'subtitles',
206
206
  label: '',
207
207
  language: '',
208
+ id: '',
208
209
  mode: 'disabled',
209
- readyState: 0,
210
210
  oncuechange: null,
211
211
  toString: function() {
212
212
  return "[object TextTrack]";
@@ -246,7 +246,7 @@ webshims.register('track', function($, webshims, window, document, undefined){
246
246
  webshims.error("cue not part of track");
247
247
  return;
248
248
  }
249
- },
249
+ }/*,
250
250
  DISABLED: 'disabled',
251
251
  OFF: 'disabled',
252
252
  HIDDEN: 'hidden',
@@ -254,7 +254,7 @@ webshims.register('track', function($, webshims, window, document, undefined){
254
254
  ERROR: 3,
255
255
  LOADED: 2,
256
256
  LOADING: 1,
257
- NONE: 0
257
+ NONE: 0*/
258
258
  };
259
259
  var copyProps = ['kind', 'label', 'srclang'];
260
260
  var copyName = {srclang: 'language'};
@@ -323,21 +323,47 @@ webshims.register('track', function($, webshims, window, document, undefined){
323
323
  if(!trackData){
324
324
  trackData = webshims.data(track, 'trackData');
325
325
  }
326
+
326
327
  if(trackData && !trackData.isTriggering){
327
328
  trackData.isTriggering = true;
328
329
  setTimeout(function(){
329
- if(!(trackData.track || {}).readyState){
330
- $(track).triggerHandler('checktrackmode');
331
- } else {
332
- $(track).closest('audio, video').triggerHandler('updatetrackdisplay');
333
- }
330
+ $(track).closest('audio, video').triggerHandler('updatetrackdisplay');
334
331
  trackData.isTriggering = false;
335
332
  }, 1);
336
333
  }
337
334
  };
338
-
335
+ var isDefaultTrack = (function(){
336
+ var defaultKinds = {
337
+ subtitles: {
338
+ subtitles: 1,
339
+ captions: 1
340
+ },
341
+ descriptions: {descriptions: 1},
342
+ chapters: {chapters: 1}
343
+ };
344
+ defaultKinds.captions = defaultKinds.subtitles;
345
+
346
+ return function(track){
347
+ var kind, firstDefaultTrack;
348
+ var isDefault = $.prop(track, 'default');
349
+ if(isDefault && (kind = $.prop(track, 'kind')) != 'metadata'){
350
+ firstDefaultTrack = $(track)
351
+ .parent()
352
+ .find('track[default]')
353
+ .filter(function(){
354
+ return !!(defaultKinds[kind][$.prop(this, 'kind')]);
355
+ })[0]
356
+ ;
357
+ if(firstDefaultTrack != track){
358
+ isDefault = false;
359
+ webshims.error('more than one default track of a specific kind detected. Fall back to default = false');
360
+ }
361
+ }
362
+ return isDefault;
363
+ };
364
+ })();
339
365
  var emptyDiv = $('<div />')[0];
340
- window.TextTrackCue = function(startTime, endTime, text){
366
+ var TextTrackCue = function(startTime, endTime, text){
341
367
  if(arguments.length != 3){
342
368
  webshims.error("wrong arguments.length for TextTrackCue.constructor");
343
369
  }
@@ -346,13 +372,11 @@ webshims.register('track', function($, webshims, window, document, undefined){
346
372
  this.endTime = endTime;
347
373
  this.text = text;
348
374
 
349
- this.id = "";
350
- this.pauseOnExit = false;
351
375
 
352
376
  createEventTarget(this);
353
377
  };
354
378
 
355
- window.TextTrackCue.prototype = {
379
+ TextTrackCue.prototype = {
356
380
 
357
381
  onenter: null,
358
382
  onexit: null,
@@ -394,6 +418,7 @@ webshims.register('track', function($, webshims, window, document, undefined){
394
418
  // align: 'middle'
395
419
  };
396
420
 
421
+ window.TextTrackCue = TextTrackCue;
397
422
 
398
423
 
399
424
 
@@ -439,23 +464,20 @@ webshims.register('track', function($, webshims, window, document, undefined){
439
464
  })();
440
465
 
441
466
  mediaelement.loadTextTrack = function(mediaelem, track, trackData, _default){
442
- var loadEvents = 'play playing timeupdate updatetrackdisplay';
467
+ var loadEvents = 'play playing updatetrackdisplay';
443
468
  var obj = trackData.track;
444
469
  var load = function(){
445
- var src = $.prop(track, 'src');
446
- var error;
447
- var ajax;
448
- if(obj.mode != 'disabled' && src && $.attr(track, 'src')){
470
+ var error, ajax, src;
471
+ if(obj.mode != 'disabled' && $.attr(track, 'src') && (src = $.prop(track, 'src'))){
449
472
  $(mediaelem).unbind(loadEvents, load);
450
- $(track).unbind('checktrackmode', load);
451
- if(!obj.readyState){
473
+ if(!trackData.readyState){
452
474
  error = function(){
453
- obj.readyState = 3;
475
+ trackData.readyState = 3;
454
476
  obj.cues = null;
455
477
  obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = null;
456
478
  $(track).triggerHandler('error');
457
479
  };
458
- obj.readyState = 1;
480
+ trackData.readyState = 1;
459
481
  try {
460
482
  obj.cues = mediaelement.createCueList();
461
483
  obj.activeCues = obj.shimActiveCues = obj._shimActiveCues = mediaelement.createCueList();
@@ -468,7 +490,7 @@ webshims.register('track', function($, webshims, window, document, undefined){
468
490
  }
469
491
  mediaelement.parseCaptions(text, obj, function(cues){
470
492
  if(cues && 'length' in cues){
471
- obj.readyState = 2;
493
+ trackData.readyState = 2;
472
494
  $(track).triggerHandler('load');
473
495
  $(mediaelem).triggerHandler('updatetrackdisplay');
474
496
  } else {
@@ -481,20 +503,18 @@ webshims.register('track', function($, webshims, window, document, undefined){
481
503
  });
482
504
  } catch(er){
483
505
  error();
484
- webshims.warn(er);
506
+ webshims.error(er);
485
507
  }
486
508
  }
487
509
  }
488
510
  };
489
- obj.readyState = 0;
511
+ trackData.readyState = 0;
490
512
  obj.shimActiveCues = null;
491
513
  obj._shimActiveCues = null;
492
514
  obj.activeCues = null;
493
515
  obj.cues = null;
494
516
  $(mediaelem).unbind(loadEvents, load);
495
- $(track).unbind('checktrackmode', load);
496
517
  $(mediaelem).on(loadEvents, load);
497
- $(track).on('checktrackmode', load);
498
518
  if(_default){
499
519
  obj.mode = showTracks[obj.kind] ? 'showing' : 'hidden';
500
520
  load();
@@ -536,9 +556,9 @@ webshims.register('track', function($, webshims, window, document, undefined){
536
556
  });
537
557
  });
538
558
  }
539
-
559
+ obj.id = $(track).prop('id');
540
560
  trackData = webshims.data(track, 'trackData', {track: obj});
541
- mediaelement.loadTextTrack(mediaelem, track, trackData, ($.prop(track, 'default') && $(track).siblings('track[default]')[ADDBACK]()[0] == track));
561
+ mediaelement.loadTextTrack(mediaelem, track, trackData, isDefaultTrack(track));
542
562
  } else {
543
563
  if(supportTrackMod){
544
564
  copyProps.forEach(function(copyProp){
@@ -553,7 +573,12 @@ webshims.register('track', function($, webshims, window, document, undefined){
553
573
  obj.mode = 'hidden';
554
574
  obj.readyState = 2;
555
575
  }
576
+ if(obj.kind == 'subtitles' && !obj.language){
577
+ webshims.error('you must provide a language for track in subtitles state');
578
+ }
579
+ obj.__wsmode = obj.mode;
556
580
  }
581
+
557
582
  return obj;
558
583
  };
559
584
 
@@ -746,9 +771,33 @@ modified for webshims
746
771
  baseData.textTracks = [];
747
772
  webshims.defineProperties(baseData.textTracks, {
748
773
  onaddtrack: {value: null},
749
- onremovetrack: {value: null}
774
+ onremovetrack: {value: null},
775
+ onchange: {value: null},
776
+ getTrackById: {
777
+ value: function(id){
778
+ var track = null;
779
+ for(var i = 0; i < baseData.textTracks.length; i++){
780
+ if(id == baseData.textTracks[i].id){
781
+ track = baseData.textTracks[i];
782
+ break;
783
+ }
784
+ }
785
+ return track;
786
+ }
787
+ }
750
788
  });
751
789
  createEventTarget(baseData.textTracks);
790
+ $(mediaelem).on('updatetrackdisplay', function(){
791
+ var track;
792
+ for(var i = 0; i < baseData.textTracks.length; i++){
793
+ track = baseData.textTracks[i];
794
+ if(track.__wsmode != track.mode){
795
+ track.__wsmode = track.mode;
796
+ $([ baseData.textTracks ]).triggerHandler('change');
797
+ }
798
+ }
799
+ });
800
+
752
801
  }
753
802
  return baseData.textTracks;
754
803
  };
@@ -803,10 +852,6 @@ modified for webshims
803
852
  if(!supportTrackMod){
804
853
  trackData.track[name] = $.prop(this, copyProp);
805
854
  }
806
- clearTimeout(trackData.changedTrackPropTimer);
807
- trackData.changedTrackPropTimer = setTimeout(function(){
808
- $(track).trigger('updatesubtitlestate');
809
- }, 1);
810
855
  }
811
856
  });
812
857
  });
@@ -843,7 +888,8 @@ modified for webshims
843
888
  },
844
889
  readyState: {
845
890
  get: function(){
846
- return ($.prop(this, 'track') || {readyState: 0}).readyState;
891
+
892
+ return (webshims.data(this, 'trackData') || {readyState: 0}).readyState;
847
893
  },
848
894
  writeable: false
849
895
  },
@@ -961,7 +1007,7 @@ modified for webshims
961
1007
  });
962
1008
  });
963
1009
 
964
- if(Modernizr.track){
1010
+ if(Modernizr.texttrackapi){
965
1011
  $('video, audio').trigger('trackapichange');
966
1012
  }
967
1013
  });
@@ -1,1129 +1,1821 @@
1
- webshims.register('form-validation', function($, webshims, window, document, undefined, options){
2
- var isWebkit = 'webkitURL' in window;
3
- var chromeBugs = isWebkit && Modernizr.formvalidation && !webshims.bugs.bustedValidity;
4
- var webkitVersion = chromeBugs && parseFloat((navigator.userAgent.match(/Safari\/([\d\.]+)/) || ['', '999999'])[1], 10);
5
- var invalidClass = options.iVal.errorClass || 'user-error';
6
- var validClass = options.iVal.successClass || 'user-success';
7
-
8
- var invalidWrapperClass = options.iVal.errorWrapperClass || 'ws-invalid';
9
- var successWrapperClass = options.iVal.successWrapperClass || 'ws-success';
10
- var errorBoxClass = options.iVal.errorBoxClass || 'ws-errorbox';
11
- var checkTypes = {checkbox: 1, radio: 1};
12
-
13
- var emptyJ = $([]);
14
- var isValid = function(elem){
15
- return ($.prop(elem, 'validity') || {valid: 1}).valid;
16
- };
17
-
18
- var nonFormFilter = function(){
19
- return !$.prop(this, 'form');
20
- };
21
- var getGroupElements = function(elem){
22
- elem = $(elem);
23
- var name;
24
- var form;
25
- var ret = emptyJ;
26
- if(elem[0].type == 'radio'){
27
- form = elem.prop('form');
28
- name = elem[0].name;
29
- if(!name){
30
- ret = elem;
31
- } else if(form){
32
- ret = $(form).jProp(name);
33
- } else {
34
- ret = $(document.getElementsByName(name)).filter(nonFormFilter);
35
- }
36
- ret = ret.filter('[type="radio"]');
37
- }
38
- return ret;
39
- };
40
-
41
-
42
- var returnValidityCause = function(validity, elem){
43
- var ret;
44
- $.each(validity, function(name, value){
45
- if(value){
46
- ret = name + $.prop(elem, 'validationMessage');
47
- return false;
48
- }
49
- });
50
- return ret;
51
- };
52
-
53
- var isInGroup = function(name){
54
- var ret;
55
- try {
56
- ret = document.activeElement.name === name;
57
- } catch(e){}
58
- return ret;
59
- };
60
- //actually we could always use the change event, but chrome messed it up and does not respect the commit action definition of the html spec
61
- //see: http://code.google.com/p/chromium/issues/detail?id=155747
62
- var changeTypes = {
1
+ webshims.register('form-shim-extend', function($, webshims, window, document, undefined, options){
2
+ "use strict";
3
+ webshims.inputTypes = webshims.inputTypes || {};
4
+ //some helper-functions
5
+ var cfg = webshims.cfg.forms;
6
+ var bugs = webshims.bugs;
7
+ var isSubmit;
8
+
9
+ var isNumber = function(string){
10
+ return (typeof string == 'number' || (string && string == string * 1));
11
+ },
12
+ typeModels = webshims.inputTypes,
13
+ checkTypes = {
63
14
  radio: 1,
64
- checkbox: 1,
65
- 'select-one': 1,
66
- 'select-multiple': 1,
67
- file: 1,
68
- date: 1,
69
- month: 1,
70
- week: 1,
71
- text: 1
72
- };
73
- //see: http://code.google.com/p/chromium/issues/detail?id=179708 and bug above
74
- var noFocusWidgets = {
75
- time: 1,
76
- date: 1,
77
- month: 1,
78
- datetime: 1,
79
- week: 1,
80
- 'datetime-local': 1
81
- };
82
- var switchValidityClass = function(e){
83
- if(!options.iVal.sel){return;}
84
- var elem, timer, shadowElem, shadowType;
85
- if(!e.target){return;}
86
- elem = $(e.target).getNativeElement()[0];
87
- shadowElem = $(elem).getShadowElement();
88
- if(elem.type == 'submit' || !$.prop(elem, 'willValidate') || (e.type == 'change' && (shadowType = shadowElem.prop('type')) && !changeTypes[shadowType])){return;}
89
- timer = $.data(elem, 'webshimsswitchvalidityclass');
90
- var switchClass = function(){
91
- if(!shadowType){
92
- shadowType = shadowElem.prop('type');
93
- }
94
- if(
95
- (chromeBugs && (e.type == 'change' || webkitVersion < 537.36) && noFocusWidgets[shadowType] && $(e.target).is(':focus')) ||
96
- (e.type == 'focusout' && elem.type == 'radio' && isInGroup(elem.name))
97
- ){
98
- return;
99
- }
100
- if(webshims.refreshCustomValidityRules){
101
- if(webshims.refreshCustomValidityRules(elem) == 'async'){
102
- $(elem).one('refreshvalidityui', switchValidityClass);
103
- return;
104
- }
105
- }
106
-
107
- var validity = $.prop(elem, 'validity');
108
-
109
- var addClass, removeClass, trigger, generaltrigger, validityCause;
110
-
111
-
112
-
113
- if(validity.valid){
114
- if(!shadowElem.hasClass(validClass)){
115
- addClass = validClass;
116
- removeClass = invalidClass;
117
- generaltrigger = 'changedvaliditystate';
118
- trigger = 'changedvalid';
119
- if(checkTypes[elem.type] && elem.checked){
120
- getGroupElements(elem).not(elem).removeClass(removeClass).addClass(addClass).removeAttr('aria-invalid');
121
- }
122
- shadowElem.removeAttr('aria-invalid');
123
- $.removeData(elem, 'webshimsinvalidcause');
124
- }
125
- } else {
126
- validityCause = returnValidityCause(validity, elem);
127
- if($.data(elem, 'webshimsinvalidcause') != validityCause){
128
- $.data(elem, 'webshimsinvalidcause', validityCause);
129
- generaltrigger = 'changedvaliditystate';
130
- }
131
- if(!shadowElem.hasClass(invalidClass)){
132
- addClass = invalidClass;
133
- removeClass = validClass;
134
- if (checkTypes[elem.type] && !elem.checked) {
135
- getGroupElements(elem).not(elem).removeClass(removeClass).addClass(addClass).attr('aria-invalid', 'true');
15
+ checkbox: 1
16
+ },
17
+ getType = function(elem){
18
+ return (elem.getAttribute('type') || elem.type || '').toLowerCase();
19
+ }
20
+ ;
21
+
22
+ (function(){
23
+ if('querySelector' in document){
24
+ try {
25
+ bugs.findRequired = !($('<form action="#" style="width: 1px; height: 1px; overflow: hidden;"><select name="b" required="" /></form>')[0].querySelector('select:required'));
26
+ } catch(er){
27
+ bugs.findRequired = false;
28
+ }
29
+
30
+ if (bugs.bustedValidity || bugs.findRequired) {
31
+ (function(){
32
+ var find = $.find;
33
+ var matchesSelector = $.find.matchesSelector;
34
+
35
+ var regExp = /(\:valid|\:invalid|\:optional|\:required|\:in-range|\:out-of-range)(?=[\s\[\~\.\+\>\:\#*]|$)/ig;
36
+ var regFn = function(sel){
37
+ return sel + '-element';
38
+ };
39
+
40
+ $.find = (function(){
41
+ var slice = Array.prototype.slice;
42
+ var fn = function(sel){
43
+ var ar = arguments;
44
+ ar = slice.call(ar, 1, ar.length);
45
+ ar.unshift(sel.replace(regExp, regFn));
46
+ return find.apply(this, ar);
47
+ };
48
+ for (var i in find) {
49
+ if(find.hasOwnProperty(i)){
50
+ fn[i] = find[i];
51
+ }
136
52
  }
137
- shadowElem.attr('aria-invalid', 'true');
138
- trigger = 'changedinvalid';
53
+ return fn;
54
+ })();
55
+ if(!Modernizr.prefixed || Modernizr.prefixed("matchesSelector", document.documentElement)){
56
+ $.find.matchesSelector = function(node, expr){
57
+ expr = expr.replace(regExp, regFn);
58
+ return matchesSelector.call(this, node, expr);
59
+ };
139
60
  }
140
- }
141
-
142
- if(addClass){
143
- shadowElem.addClass(addClass).removeClass(removeClass);
144
- //jQuery 1.6.1 IE9 bug (doubble trigger bug)
145
- setTimeout(function(){
146
- $(elem).trigger(trigger);
147
- }, 0);
148
- }
149
- if(generaltrigger){
150
- setTimeout(function(){
151
- $(elem).trigger(generaltrigger);
152
- }, 0);
153
- }
154
-
155
- $.removeData(elem, 'webshimsswitchvalidityclass');
156
- };
157
-
158
- if(timer){
159
- clearTimeout(timer);
61
+
62
+ })();
160
63
  }
161
- if(e.type == 'refreshvalidityui'){
162
- switchClass();
64
+ }
65
+ })();
66
+
67
+ //API to add new input types
68
+ webshims.addInputType = function(type, obj){
69
+ typeModels[type] = obj;
70
+ };
71
+
72
+ //contsrain-validation-api
73
+ var validityPrototype = {
74
+ customError: false,
75
+
76
+ typeMismatch: false,
77
+ badInput: false,
78
+ rangeUnderflow: false,
79
+ rangeOverflow: false,
80
+ stepMismatch: false,
81
+ tooLong: false,
82
+ patternMismatch: false,
83
+ valueMissing: false,
84
+
85
+ valid: true
86
+ };
87
+
88
+ var isPlaceholderOptionSelected = function(select){
89
+ if(select.type == 'select-one' && select.size < 2){
90
+ var option = $('> option:first-child', select);
91
+ return !!option.prop('selected');
92
+ }
93
+ return false;
94
+ };
95
+
96
+ var emptyJ = $([]);
97
+ var getGroupElements = function(elem){
98
+ elem = $(elem);
99
+ var name;
100
+ var form;
101
+ var ret = emptyJ;
102
+ if(elem[0].type == 'radio'){
103
+ form = elem.prop('form');
104
+ name = elem[0].name;
105
+ if(!name){
106
+ ret = elem;
107
+ } else if(form){
108
+ ret = $(form[name]);
163
109
  } else {
164
- $.data(elem, 'webshimsswitchvalidityclass', setTimeout(switchClass, 9));
110
+ ret = $(document.getElementsByName(name)).filter(function(){
111
+ return !$.prop(this, 'form');
112
+ });
165
113
  }
166
- };
167
-
168
- $(document.body || 'html')
169
- .on(options.validityUIEvents || 'focusout change refreshvalidityui invalid', switchValidityClass)
170
- .on('reset resetvalui', function(e){
171
- var elems = $(e.target);
172
- if(e.type == 'reset'){
173
- elems = elems.filter('form').jProp('elements');
114
+ ret = ret.filter('[type="radio"]');
115
+ }
116
+ return ret;
117
+ };
118
+ var validityRules = {
119
+ valueMissing: function(input, val, cache){
120
+ if(!input.prop('required')){return false;}
121
+ var ret = false;
122
+ if(!('type' in cache)){
123
+ cache.type = getType(input[0]);
174
124
  }
175
- elems
176
- .filter('.user-error, .user-success')
177
- .removeAttr('aria-invalid')
178
- .removeClass('user-error')
179
- .removeClass('user-success')
180
- .getNativeElement()
181
- .each(function(){
182
- $.removeData(this, 'webshimsinvalidcause');
183
- })
184
- .trigger('resetvalidityui')
185
- ;
186
- })
187
- ;
188
-
189
- var setRoot = function(){
190
- webshims.scrollRoot = (isWebkit || document.compatMode == 'BackCompat') ?
191
- $(document.body) :
192
- $(document.documentElement)
193
- ;
194
- };
195
- var minWidth = (Modernizr.boxSizing || Modernizr['display-table'] || $.support.getSetAttribute || $.support.boxSizing) ?
196
- 'minWidth' :
197
- 'width'
198
- ;
199
- var hasTransition = ('transitionDelay' in document.documentElement.style);
200
- var resetPos = {display: 'inline-block', left: 0, top: 0, marginTop: 0, marginLeft: 0, marginRight: 0, marginBottom: 0};
201
-
202
- setRoot();
203
- webshims.ready('DOM', setRoot);
204
-
205
-
206
- webshims.getRelOffset = function(posElem, relElem, opts){
207
- var offset, bodyOffset, dirs;
208
- posElem = $(posElem);
209
- $.swap($(posElem)[0], resetPos, function(){
210
- if($.position && opts && $.position.getScrollInfo){
211
- if(!opts.of){
212
- opts.of = relElem;
213
- }
214
-
215
- opts.using = function(calced, data){
216
- posElem.attr({'data-horizontal': data.horizontal, 'data-vertical': data.vertical});
217
- offset = calced;
218
- };
219
- posElem.attr({
220
- 'data-horizontal': '',
221
- 'data-vertical': '',
222
- 'data-my': opts.my || 'center',
223
- 'data-at': opts.at || 'center'
224
- });
225
- posElem.position(opts);
226
-
125
+ if(cache.nodeName == 'select'){
126
+ ret = (!val && (input[0].selectedIndex < 0 || isPlaceholderOptionSelected(input[0]) ));
127
+ } else if(checkTypes[cache.type]){
128
+ ret = (cache.type == 'checkbox') ? !input.is(':checked') : !getGroupElements(input).filter(':checked')[0];
227
129
  } else {
228
- offset = $(relElem).offset();
229
- bodyOffset = posElem.offset();
230
- offset.top -= bodyOffset.top;
231
- offset.left -= bodyOffset.left;
232
-
233
- offset.top += relElem.outerHeight();
130
+ ret = !(val);
234
131
  }
235
-
236
- });
132
+ return ret;
133
+ },
134
+ tooLong: function(){
135
+ return false;
136
+ },
137
+ patternMismatch: function(input, val, cache) {
138
+ if(val === '' || cache.nodeName == 'select'){return false;}
139
+ var pattern = input.attr('pattern');
140
+ if(!pattern){return false;}
141
+ try {
142
+ pattern = new RegExp('^(?:' + pattern + ')$');
143
+ } catch(er){
144
+ webshims.error('invalid pattern value: "'+ pattern +'" | '+ er);
145
+ pattern = false;
146
+ }
147
+ if(!pattern){return false;}
148
+ return !(pattern.test(val));
149
+ }
150
+ }
151
+ ;
152
+
153
+ $.each({typeMismatch: 'mismatch', badInput: 'bad'}, function(name, fn){
154
+ validityRules[name] = function (input, val, cache){
155
+ if(val === '' || cache.nodeName == 'select'){return false;}
156
+ var ret = false;
157
+ if(!('type' in cache)){
158
+ cache.type = getType(input[0]);
159
+ }
237
160
 
238
- return offset;
161
+ if(typeModels[cache.type] && typeModels[cache.type][fn]){
162
+ ret = typeModels[cache.type][fn](val, input);
163
+ } else if('validity' in input[0] && ('name' in input[0].validity)){
164
+ ret = input[0].validity[name] || false;
165
+ }
166
+ return ret;
239
167
  };
240
-
241
- $.extend(webshims.wsPopover, {
168
+ });
169
+
170
+ webshims.addValidityRule = function(type, fn){
171
+ validityRules[type] = fn;
172
+ };
173
+
174
+ $.event.special.invalid = {
175
+ add: function(){
176
+ $.event.special.invalid.setup.call(this.form || this);
177
+ },
178
+ setup: function(){
179
+ var form = this.form || this;
180
+ if( $.data(form, 'invalidEventShim') ){
181
+ form = null;
182
+ return;
183
+ }
184
+ $(form)
185
+ .data('invalidEventShim', true)
186
+ .on('submit', $.event.special.invalid.handler)
187
+ ;
188
+ webshims.moveToFirstEvent(form, 'submit');
189
+ if(webshims.bugs.bustedValidity && $.nodeName(form, 'form')){
190
+ (function(){
191
+ var noValidate = form.getAttribute('novalidate');
192
+ form.setAttribute('novalidate', 'novalidate');
193
+ webshims.data(form, 'bustedNoValidate', (noValidate == null) ? null : noValidate);
194
+ })();
195
+ }
196
+ form = null;
197
+ },
198
+ teardown: $.noop,
199
+ handler: function(e, d){
242
200
 
201
+ if( e.type != 'submit' || e.testedValidity || !e.originalEvent || !$.nodeName(e.target, 'form') || $.prop(e.target, 'noValidate') ){return;}
243
202
 
244
- isInElement: function(container, contained){
245
- return container == contained || $.contains(container, contained);
246
- },
247
- show: function(element){
248
- if(this.isVisible){return;}
249
- var e = $.Event('wspopoverbeforeshow');
250
- this.element.trigger(e);
251
- if(e.isDefaultPrevented()){return;}
252
- this.isVisible = true;
253
- element = $(element || this.options.prepareFor).getNativeElement() ;
254
-
255
- var that = this;
256
- var visual = $(element).getShadowElement();
257
- var delayedRepos = function(e){
258
- clearTimeout(that.timers.repos);
259
- that.timers.repos = setTimeout(function(){
260
- that.position(visual);
261
- }, e && e.type == 'pospopover' ? 4 : 200);
262
- };
203
+ isSubmit = true;
204
+ e.testedValidity = true;
205
+ var notValid = !($(e.target).checkValidity());
206
+ if(notValid){
207
+ e.stopImmediatePropagation();
208
+ isSubmit = false;
209
+ return false;
210
+ }
211
+ isSubmit = false;
212
+ }
213
+ };
214
+
215
+ $.event.special.submit = $.event.special.submit || {setup: function(){return false;}};
216
+ var submitSetup = $.event.special.submit.setup;
217
+ $.extend($.event.special.submit, {
218
+ setup: function(){
219
+ if($.nodeName(this, 'form')){
220
+ $(this).on('invalid', $.noop);
221
+ } else {
222
+ $('form', this).on('invalid', $.noop);
223
+ }
224
+ return submitSetup.apply(this, arguments);
225
+ }
226
+ });
227
+ webshims.ready('form-shim-extend2 WINDOWLOAD', function(){
228
+ $(window).on('invalid', $.noop);
229
+ });
263
230
 
264
- this.clear();
265
- this.element.removeClass('ws-po-visible').css('display', 'none');
231
+
232
+ webshims.addInputType('email', {
233
+ mismatch: (function(){
234
+ //taken from http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address
235
+ var test = cfg.emailReg || /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
236
+ var splitReg = /\s*,\s*/g;
237
+ return function(val, input){
238
+ var ret = false;
239
+ val = $(input).prop('multiple') ? val.split(splitReg) : [val];
266
240
 
267
- this.prepareFor(element, visual);
241
+ for(var i = 0; i < val.length; i++){
242
+ if(!test.test(val[i])){
243
+ ret = true;
244
+ break;
245
+ }
246
+ }
247
+ return ret;
248
+ };
249
+ })()
250
+ });
251
+
252
+ webshims.addInputType('url', {
253
+ mismatch: (function(){
254
+ //taken from scott gonzales
255
+ var test = cfg.urlReg || /^([a-z]([a-z]|\d|\+|-|\.)*):(\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?((\[(|(v[\da-f]{1,}\.(([a-z]|\d|-|\.|_|~)|[!\$&'\(\)\*\+,;=]|:)+))\])|((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=])*)(:\d*)?)(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*|(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)){0})(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i;
256
+ return function(val){
257
+ return !test.test(val);
258
+ };
259
+ })()
260
+ });
261
+
262
+ webshims.defineNodeNameProperty('input', 'type', {
263
+ prop: {
264
+ get: function(){
265
+ var elem = this;
266
+ var type = (elem.getAttribute('type') || '').toLowerCase();
267
+ return (webshims.inputTypes[type]) ? type : elem.type;
268
+ }
269
+ }
270
+ });
271
+
272
+ // IDLs for constrain validation API
273
+ //ToDo: add object to this list
274
+ webshims.defineNodeNamesProperties(['button', 'fieldset', 'output'], {
275
+ checkValidity: {
276
+ value: function(){return true;}
277
+ },
278
+ willValidate: {
279
+ value: false
280
+ },
281
+ setCustomValidity: {
282
+ value: $.noop
283
+ },
284
+ validity: {
285
+ writeable: false,
286
+ get: function(){
287
+ return $.extend({}, validityPrototype);
288
+ }
289
+ }
290
+ }, 'prop');
291
+
292
+ var baseCheckValidity = function(elem){
293
+ var e,
294
+ v = $.prop(elem, 'validity')
295
+ ;
296
+ if(v){
297
+ $.data(elem, 'cachedValidity', v);
298
+ } else {
299
+ return true;
300
+ }
301
+ if( !v.valid ){
302
+ e = $.Event('invalid');
303
+ var jElm = $(elem).trigger(e);
304
+ if(isSubmit && !baseCheckValidity.unhandledInvalids && !e.isDefaultPrevented()){
305
+ webshims.validityAlert.showFor(jElm);
306
+ baseCheckValidity.unhandledInvalids = true;
307
+ }
308
+ }
309
+ $.removeData(elem, 'cachedValidity');
310
+ return v.valid;
311
+ };
312
+ var rsubmittable = /^(?:select|textarea|input)/i;
313
+ webshims.defineNodeNameProperty('form', 'checkValidity', {
314
+ prop: {
315
+ value: function(){
268
316
 
269
- this.position(visual);
270
- that.timers.show = setTimeout(function(){
271
- that.element.css('display', '');
272
- that.timers.show = setTimeout(function(){
273
- that.element.addClass('ws-po-visible').trigger('wspopovershow');
274
- }, 9);
275
- }, 9);
317
+ var ret = true,
318
+ elems = $($.prop(this, 'elements')).filter(function(){
319
+ if(!rsubmittable.test(this.nodeName)){return false;}
320
+ var shadowData = webshims.data(this, 'shadowData');
321
+ return !shadowData || !shadowData.nativeElement || shadowData.nativeElement === this;
322
+ })
323
+ ;
276
324
 
277
- $(document).on('focusin'+this.eventns+' mousedown'+this.eventns, function(e){
278
- if(that.options.hideOnBlur && !that.stopBlur && !that.isInElement(that.lastElement[0] || document.body, e.target) && !that.isInElement(element[0] || document.body, e.target) && !that.isInElement(that.element[0], e.target)){
279
- that.hide();
325
+ baseCheckValidity.unhandledInvalids = false;
326
+ for(var i = 0, len = elems.length; i < len; i++){
327
+ if( !baseCheckValidity(elems[i]) ){
328
+ ret = false;
280
329
  }
281
- });
282
-
283
- this.element.off('pospopover').on('pospopover', delayedRepos);
284
- $(window).on('resize'+this.eventns + ' pospopover'+this.eventns, delayedRepos);
285
- },
286
- prepareFor: function(element, visual){
287
- var onBlur;
288
- var that = this;
289
- var css = {};
290
- var opts = $.extend(true, {}, this.options, $(element.prop('form') || []).data('wspopover') || {}, element.data('wspopover'));
291
- this.lastOpts = opts;
292
- this.lastElement = $(element).getShadowFocusElement();
293
- if(!this.prepared || !this.options.prepareFor){
294
- if(opts.appendTo == 'element'){
295
- this.element.insertAfter(element);
296
- } else {
297
- this.element.appendTo(opts.appendTo);
330
+ }
331
+ return ret;
332
+ }
333
+ }
334
+ });
335
+
336
+ webshims.defineNodeNamesProperties(['input', 'textarea', 'select'], {
337
+ checkValidity: {
338
+ value: function(){
339
+ baseCheckValidity.unhandledInvalids = false;
340
+ return baseCheckValidity($(this).getNativeElement()[0]);
341
+ }
342
+ },
343
+ setCustomValidity: {
344
+ value: function(error){
345
+ $.removeData(this, 'cachedValidity');
346
+ webshims.data(this, 'customvalidationMessage', ''+error);
347
+ }
348
+ },
349
+ willValidate: {
350
+ writeable: false,
351
+ get: (function(){
352
+ var types = {
353
+ button: 1,
354
+ reset: 1,
355
+ hidden: 1,
356
+ image: 1
298
357
  }
358
+ ;
359
+ return function(){
360
+ var elem = $(this).getNativeElement()[0];
361
+ //elem.name && <- we don't use to make it easier for developers
362
+ return !!(!elem.disabled && !elem.readOnly && !types[elem.type] );
363
+ };
364
+ })()
365
+ },
366
+ validity: {
367
+ writeable: false,
368
+ get: function(){
369
+ var jElm = $(this).getNativeElement();
370
+ var elem = jElm[0];
371
+ var validityState = $.data(elem, 'cachedValidity');
372
+ if(validityState){
373
+ return validityState;
299
374
  }
375
+ validityState = $.extend({}, validityPrototype);
300
376
 
301
- this.element.attr({
302
- 'data-class': element.prop('className'),
303
- 'data-id': element.prop('id')
304
- });
305
-
306
- css[minWidth] = opts.constrainWidth ? visual.outerWidth() : '';
307
-
308
- this.element.css(css);
309
-
310
- if(opts.hideOnBlur){
311
- onBlur = function(e){
312
- if(that.stopBlur){
313
- e.stopImmediatePropagation();
314
- } else {
315
- that.hide();
316
- }
317
- };
318
-
319
- that.timers.bindBlur = setTimeout(function(){
320
- that.lastElement.off(that.eventns).on('focusout'+that.eventns + ' blur'+that.eventns, onBlur);
321
- that.lastElement.getNativeElement().off(that.eventns);
322
- }, 10);
323
-
324
-
377
+ if( !$.prop(elem, 'willValidate') || elem.type == 'submit' ){
378
+ return validityState;
325
379
  }
380
+ var val = jElm.val(),
381
+ cache = {nodeName: elem.nodeName.toLowerCase()}
382
+ ;
326
383
 
327
- if(!this.prepared && $.fn.bgIframe){
328
- this.element.bgIframe();
384
+ validityState.customError = !!(webshims.data(elem, 'customvalidationMessage'));
385
+ if( validityState.customError ){
386
+ validityState.valid = false;
329
387
  }
330
- this.prepared = true;
331
- },
332
- clear: function(){
333
- $(window).off(this.eventns);
334
- $(document).off(this.eventns);
335
- this.element.off('transitionend'+this.eventns);
336
- this.stopBlur = false;
337
- this.lastOpts = false;
338
- $.each(this.timers, function(timerName, val){
339
- clearTimeout(val);
340
- });
341
- },
342
- hide: function(){
343
- var e = $.Event('wspopoverbeforehide');
344
- this.element.trigger(e);
345
- if(e.isDefaultPrevented() || !this.isVisible){return;}
346
- this.isVisible = false;
347
- var that = this;
348
- var forceHide = function(e){
349
- if(!(e && e.type == 'transitionend' && (e = e.originalEvent) && e.target == that.element[0] && that.element.css('visibility') == 'hidden')){
350
- that.element.off('transitionend'+that.eventns).css('display', 'none').attr({'data-id': '', 'data-class': '', 'hidden': 'hidden'});
351
- clearTimeout(that.timers.forcehide);
352
- $(window).off('resize'+that.eventns);
388
+
389
+ $.each(validityRules, function(rule, fn){
390
+ if (fn(jElm, val, cache)) {
391
+ validityState[rule] = true;
392
+ validityState.valid = false;
353
393
  }
354
- };
355
- this.clear();
356
- this.element.removeClass('ws-po-visible').trigger('wspopoverhide');
357
- $(window).on('resize'+this.eventns, forceHide);
358
- if(hasTransition){
359
- this.element.off('transitionend'+this.eventns).on('transitionend'+this.eventns, forceHide);
394
+ });
395
+ $(this).getShadowFocusElement().attr('aria-invalid', validityState.valid ? 'false' : 'true');
396
+ jElm = null;
397
+ elem = null;
398
+ return validityState;
399
+ }
400
+ }
401
+ }, 'prop');
402
+
403
+ webshims.defineNodeNamesBooleanProperty(['input', 'textarea', 'select'], 'required', {
404
+ set: function(value){
405
+ $(this).getShadowFocusElement().attr('aria-required', !!(value)+'');
406
+ },
407
+ initAttr: Modernizr.localstorage //only if we have aria-support
408
+ });
409
+ webshims.defineNodeNamesBooleanProperty(['input'], 'multiple');
410
+
411
+ if(webshims.bugs.bustedValidity){
412
+
413
+ webshims.defineNodeNameProperty('form', 'novalidate', {
414
+ attr: {
415
+ set: function(val){
416
+ webshims.data(this, 'bustedNoValidate', ''+val);
417
+ },
418
+ get: function(){
419
+ var ret = webshims.data(this, 'bustedNoValidate');
420
+ return ret == null ? undefined : ret;
360
421
  }
361
-
362
- that.timers.forcehide = setTimeout(forceHide, hasTransition ? 600 : 40);
363
422
  },
364
- position: function(element){
365
- var offset = webshims.getRelOffset(this.element.removeAttr('hidden'), element, (this.lastOpts || this.options).position);
366
-
367
- this.element.css(offset);
423
+ removeAttr: {
424
+ value: function(){
425
+ webshims.data(this, 'bustedNoValidate', null);
426
+ }
368
427
  }
369
428
  });
370
429
 
430
+ $.each(['rangeUnderflow', 'rangeOverflow', 'stepMismatch'], function(i, name){
431
+ validityRules[name] = function(elem){
432
+ return (elem[0].validity || {})[name] || false;
433
+ };
434
+ });
371
435
 
372
-
373
- /* some extra validation UI */
374
- webshims.validityAlert = (function(){
375
-
376
- options.messagePopover.position = $.extend({}, {
377
- at: 'left bottom',
378
- my: 'left top',
379
- collision: 'none'
380
- }, options.messagePopover.position || {});
381
-
382
- var focusTimer = false;
383
-
384
- var api = webshims.objectCreate(webshims.wsPopover, {}, options.messagePopover);
385
- var boundHide = api.hide.bind(api);
436
+ }
437
+
438
+ webshims.defineNodeNameProperty('form', 'noValidate', {
439
+ prop: {
440
+ set: function(val){
441
+ val = !!val;
442
+ if(val){
443
+ $.attr(this, 'novalidate', 'novalidate');
444
+ } else {
445
+ $(this).removeAttr('novalidate');
446
+ }
447
+ },
448
+ get: function(){
449
+ return $.attr(this, 'novalidate') != null;
450
+ }
451
+ }
452
+ });
453
+
454
+ if(Modernizr.inputtypes.date && /webkit/i.test(navigator.userAgent)){
455
+ (function(){
386
456
 
387
- api.element.addClass('validity-alert').attr({role: 'alert'});
388
- $.extend(api, {
389
- hideDelay: 5000,
390
- showFor: function(elem, message, noFocusElem, noBubble){
391
-
392
- elem = $(elem).getNativeElement();
393
- this.clear();
394
- this.hide();
395
- if(!noBubble){
396
- this.getMessage(elem, message);
397
-
398
- this.show(elem);
399
- if(this.hideDelay){
400
- this.timers.delayedHide = setTimeout(boundHide, this.hideDelay);
401
- }
402
-
403
- }
404
-
405
- if(!noFocusElem){
406
- this.setFocus(elem);
407
- }
457
+ var noInputTriggerEvts = {updateInput: 1, input: 1},
458
+ fixInputTypes = {
459
+ date: 1,
460
+ time: 1,
461
+ month: 1,
462
+ week: 1,
463
+ "datetime-local": 1
408
464
  },
409
- setFocus: function(element){
410
- var focusElem = $(element).getShadowFocusElement();
411
- var scrollTop = webshims.scrollRoot.scrollTop();
412
- var elemTop = focusElem.offset().top - 30;
413
- var focus = function(){
414
- try {
415
- focusElem[0].focus();
416
- } catch(e){}
417
- $(window).triggerHandler('pospopover'+this.eventns);
418
- };
419
-
420
- if(scrollTop > elemTop){
421
- webshims.scrollRoot.animate(
422
- {scrollTop: elemTop - 5},
423
- {
424
- queue: false,
425
- duration: Math.max( Math.min( 600, (scrollTop - elemTop) * 1.5 ), 80 ),
426
- complete: focus
465
+ noFocusEvents = {
466
+ focusout: 1,
467
+ blur: 1
468
+ },
469
+ changeEvts = {
470
+ updateInput: 1,
471
+ change: 1
472
+ },
473
+ observe = function(input){
474
+ var timer,
475
+ focusedin = true,
476
+ lastInputVal = input.prop('value'),
477
+ lastChangeVal = lastInputVal,
478
+ trigger = function(e){
479
+ //input === null
480
+ if(!input){return;}
481
+ var newVal = input.prop('value');
482
+
483
+ if(newVal !== lastInputVal){
484
+ lastInputVal = newVal;
485
+ if(!e || !noInputTriggerEvts[e.type]){
486
+ input.trigger('input');
487
+ }
427
488
  }
428
- );
429
-
430
- } else {
431
- focus();
432
- }
489
+ if(e && changeEvts[e.type]){
490
+ lastChangeVal = newVal;
491
+ }
492
+ if(!focusedin && newVal !== lastChangeVal){
493
+ input.trigger('change');
494
+ }
495
+ },
496
+ extraTimer,
497
+ extraTest = function(){
498
+ clearTimeout(extraTimer);
499
+ extraTimer = setTimeout(trigger, 9);
500
+ },
501
+ unbind = function(e){
502
+ clearInterval(timer);
503
+ setTimeout(function(){
504
+ if(e && noFocusEvents[e.type]){
505
+ focusedin = false;
506
+ }
507
+ if(input){
508
+ input.unbind('focusout blur', unbind).unbind('input change updateInput', trigger);
509
+ trigger();
510
+ }
511
+ input = null;
512
+ }, 1);
513
+
514
+ }
515
+ ;
433
516
 
434
- },
435
- getMessage: function(elem, message){
436
- if (!message) {
437
- message = elem.getErrorMessage();
438
- }
439
- if (message) {
440
- api.contentElement.text(message);
441
- } else {
442
- this.hide();
443
- }
517
+ clearInterval(timer);
518
+ timer = setInterval(trigger, 160);
519
+ extraTest();
520
+ input
521
+ .off({
522
+ 'focusout blur': unbind,
523
+ 'input change updateInput': trigger
524
+ })
525
+ .on({
526
+ 'focusout blur': unbind,
527
+ 'input updateInput change': trigger
528
+ })
529
+ ;
444
530
  }
445
- });
531
+ ;
532
+
533
+
534
+ $(document)
535
+ .on('focusin', function(e){
536
+ if( e.target && fixInputTypes[e.target.type] && !e.target.readOnly && !e.target.disabled ){
537
+ observe($(e.target));
538
+ }
539
+ })
540
+ ;
446
541
 
447
542
 
448
- return api;
449
543
  })();
544
+ }
545
+
546
+ webshims.addReady(function(context, contextElem){
547
+ //start constrain-validation
548
+ var focusElem;
549
+ $('form', context)
550
+ .add(contextElem.filter('form'))
551
+ .bind('invalid', $.noop)
552
+ ;
450
553
 
451
- var fx = {
452
- slide: {
453
- show: 'slideDown',
454
- hide: 'slideUp'
455
- },
456
- fade: {
457
- show: 'fadeIn',
458
- hide: 'fadeOut'
554
+ try {
555
+ if(context == document && !('form' in (document.activeElement || {}))) {
556
+ focusElem = $('input[autofocus], select[autofocus], textarea[autofocus]', context).eq(0).getShadowFocusElement()[0];
557
+ if (focusElem && focusElem.offsetHeight && focusElem.offsetWidth) {
558
+ focusElem.focus();
559
+ }
459
560
  }
460
- };
461
- if(!fx[options.iVal.fx]){
462
- options.iVal.fx = 'slide';
463
- }
464
- webshims.errorbox = {
465
- create: function(elem, fieldWrapper){
466
- if(!fieldWrapper){
467
- fieldWrapper = this.getFieldWrapper(elem);
561
+ }
562
+ catch (er) {}
563
+
564
+ });
565
+
566
+ if(!Modernizr.input.list){
567
+ webshims.defineNodeNameProperty('datalist', 'options', {
568
+ prop: {
569
+ writeable: false,
570
+ get: function(){
571
+ var elem = this;
572
+ var select = $('select', elem);
573
+ var options;
574
+ if(select[0]){
575
+ options = $.makeArray(select[0].options || []);
576
+ } else {
577
+ options = $('option', elem).get();
578
+ if(options.length){
579
+ webshims.warn('you should wrap your option-elements for a datalist in a select element to support IE and other old browsers.');
580
+ }
581
+ }
582
+ return options;
468
583
  }
469
- var errorBox = $('div.'+errorBoxClass, fieldWrapper);
584
+ }
585
+ });
586
+ }
587
+
588
+
589
+
590
+ var submitterTypes = {submit: 1, button: 1, image: 1};
591
+ var formSubmitterDescriptors = {};
592
+ [
593
+ {
594
+ name: "enctype",
595
+ limitedTo: {
596
+ "application/x-www-form-urlencoded": 1,
597
+ "multipart/form-data": 1,
598
+ "text/plain": 1
599
+ },
600
+ defaultProp: "application/x-www-form-urlencoded",
601
+ proptype: "enum"
602
+ },
603
+ {
604
+ name: "method",
605
+ limitedTo: {
606
+ "get": 1,
607
+ "post": 1
608
+ },
609
+ defaultProp: "get",
610
+ proptype: "enum"
611
+ },
612
+ {
613
+ name: "action",
614
+ proptype: "url"
615
+ },
616
+ {
617
+ name: "target"
618
+ },
619
+ {
620
+ name: "novalidate",
621
+ propName: "noValidate",
622
+ proptype: "boolean"
623
+ }
624
+ ].forEach(function(desc){
625
+ var propName = 'form'+ (desc.propName || desc.name).replace(/^[a-z]/, function(f){
626
+ return f.toUpperCase();
627
+ });
628
+ var attrName = 'form'+ desc.name;
629
+ var formName = desc.name;
630
+ var eventName = 'click.webshimssubmittermutate'+formName;
631
+
632
+ var changeSubmitter = function(){
633
+ var elem = this;
634
+ if( !('form' in elem) || !submitterTypes[elem.type] ){return;}
635
+ var form = $.prop(elem, 'form');
636
+ if(!form){return;}
637
+ var attr = $.attr(elem, attrName);
638
+ if(attr != null && ( !desc.limitedTo || attr.toLowerCase() === $.prop(elem, propName))){
470
639
 
471
- if(!errorBox.length){
472
- errorBox = $('<div class="'+ errorBoxClass +'" hidden="hidden">');
473
- fieldWrapper.append(errorBox);
474
- }
640
+ var oldAttr = $.attr(form, formName);
475
641
 
476
- fieldWrapper.data('errorbox', errorBox);
477
- return errorBox;
478
- },
479
- getFieldWrapper: function(elem){
480
- var fieldWrapper;
481
- if(options.iVal.fieldWrapper){
482
- fieldWrapper = (typeof options.iVal.fieldWrapper == "function") ? options.iVal.fieldWrapper.apply(this, arguments) : $(elem).parent().closest(options.iVal.fieldWrapper);
483
- if(!fieldWrapper.length){
484
- fieldWrapper = false;
485
- webshims.error("could not find fieldwrapper: "+ options.iVal.fieldWrapper);
642
+ $.attr(form, formName, attr);
643
+ setTimeout(function(){
644
+ if(oldAttr != null){
645
+ $.attr(form, formName, oldAttr);
646
+ } else {
647
+ try {
648
+ $(form).removeAttr(formName);
649
+ } catch(er){
650
+ form.removeAttribute(formName);
651
+ }
486
652
  }
487
- }
488
- if(!fieldWrapper){
489
- fieldWrapper = $(elem).parent().closest(':not(span, label, em, strong, b, i, mark, p)');
490
- }
491
- return fieldWrapper;
492
- },
493
- _createContentMessage: (function(){
494
- var fields = {};
495
- var getErrorName = function(elem){
496
- var ret = $(elem).data('errortype');
497
- if(!ret){
498
- $.each(fields, function(errorName, cNames){
499
- if($(elem).is(cNames)){
500
- ret = errorName;
501
- return false;
653
+ }, 9);
654
+ }
655
+ };
656
+
657
+
658
+
659
+ switch(desc.proptype) {
660
+ case "url":
661
+ var urlForm = document.createElement('form');
662
+ formSubmitterDescriptors[propName] = {
663
+ prop: {
664
+ set: function(value){
665
+ $.attr(this, attrName, value);
666
+ },
667
+ get: function(){
668
+ var value = $.attr(this, attrName);
669
+ if(value == null){return '';}
670
+ urlForm.setAttribute('action', value);
671
+ return urlForm.action;
672
+ }
673
+ }
674
+ };
675
+ break;
676
+ case "boolean":
677
+ formSubmitterDescriptors[propName] = {
678
+ prop: {
679
+ set: function(val){
680
+ val = !!val;
681
+ if(val){
682
+ $.attr(this, 'formnovalidate', 'formnovalidate');
683
+ } else {
684
+ $(this).removeAttr('formnovalidate');
502
685
  }
503
- });
686
+ },
687
+ get: function(){
688
+ return $.attr(this, 'formnovalidate') != null;
689
+ }
504
690
  }
505
- return ret || 'defaultMessage';
506
691
  };
507
- $(function(){
508
- $.each($('<input />').prop('validity'), function(name){
509
- if(name != 'valid'){
510
- var cName = name.replace(/[A-Z]/, function(c){
511
- return '-'+(c).toLowerCase();
512
- });
513
- fields[name] = '.'+cName+', .'+name+', .'+(name).toLowerCase()+', [data-errortype="'+ name +'"]';
692
+ break;
693
+ case "enum":
694
+ formSubmitterDescriptors[propName] = {
695
+ prop: {
696
+ set: function(value){
697
+ $.attr(this, attrName, value);
698
+ },
699
+ get: function(){
700
+ var value = $.attr(this, attrName);
701
+ return (!value || ( (value = value.toLowerCase()) && !desc.limitedTo[value] )) ? desc.defaultProp : value;
514
702
  }
515
- });
516
- });
517
- return function(elem, errorBox){
518
- var extended = false;
519
- var errorMessages = $(elem).data('errormessage') || {};
520
- if(typeof errorMessages == 'string'){
521
- errorMessages = {defaultMessage: errorMessages};
522
703
  }
523
- $('> *', errorBox).each(function(){
524
- var name = getErrorName(this);
525
- if(!errorMessages[name]){
526
- extended = true;
527
- errorMessages[name] = $(this).html();
704
+ };
705
+ break;
706
+ default:
707
+ formSubmitterDescriptors[propName] = {
708
+ prop: {
709
+ set: function(value){
710
+ $.attr(this, attrName, value);
711
+ },
712
+ get: function(){
713
+ var value = $.attr(this, attrName);
714
+ return (value != null) ? value : "";
528
715
  }
529
- });
530
- if(extended){
531
- $(elem).data('errormessage', errorMessages);
532
716
  }
533
717
  };
534
- })(),
535
- get: function(elem, fieldWrapper){
536
- if(!fieldWrapper){
537
- fieldWrapper = this.getFieldWrapper(elem);
538
- }
539
- var errorBox = fieldWrapper.data('errorbox');
540
- if(!errorBox){
541
- errorBox = this.create(elem, fieldWrapper);
542
- this._createContentMessage(elem, errorBox);
543
- } else if(typeof errorBox == 'string'){
544
- errorBox = $('#'+errorBox);
545
- fieldWrapper.data('errorbox', errorBox);
546
- this._createContentMessage(elem, errorBox);
547
- }
548
- return errorBox;
549
- },
550
- addSuccess: function(elem, fieldWrapper){
551
- var type = $.prop(elem, 'type');
552
- var check = function(){
553
- var hasVal = checkTypes[type] ? $.prop(elem, 'checked') : $(elem).val();
554
- fieldWrapper[hasVal ? 'addClass' : 'removeClass'](successWrapperClass);
555
- };
556
- var evt = changeTypes[type] ? 'change' : 'blur';
557
-
558
- $(elem).off('.recheckvalid').on(evt+'.recheckinvalid', check);
559
- check();
718
+ }
719
+
720
+
721
+ if(!formSubmitterDescriptors[attrName]){
722
+ formSubmitterDescriptors[attrName] = {};
723
+ }
724
+ formSubmitterDescriptors[attrName].attr = {
725
+ set: function(value){
726
+ formSubmitterDescriptors[attrName].attr._supset.call(this, value);
727
+ $(this).unbind(eventName).on(eventName, changeSubmitter);
560
728
  },
561
- hideError: function(elem, reset){
562
- var fieldWrapper = this.getFieldWrapper(elem);
563
- var errorBox = fieldWrapper.hasClass(invalidWrapperClass) ? this.get(elem, fieldWrapper) : fieldWrapper.data('errorbox');
729
+ get: function(){
730
+ return formSubmitterDescriptors[attrName].attr._supget.call(this);
731
+ }
732
+ };
733
+ formSubmitterDescriptors[attrName].initAttr = true;
734
+ formSubmitterDescriptors[attrName].removeAttr = {
735
+ value: function(){
736
+ $(this).unbind(eventName);
737
+ formSubmitterDescriptors[attrName].removeAttr._supvalue.call(this);
738
+ }
739
+ };
740
+ });
741
+
742
+ webshims.defineNodeNamesProperties(['input', 'button'], formSubmitterDescriptors);
743
+
744
+ }); //webshims.ready end
745
+
746
+ webshims.register('form-shim-extend2', function($, webshims, window, document, undefined, options){
747
+ "use strict";
748
+ var emptyJ = $([]);
749
+ var getGroupElements = function(elem){
750
+ elem = $(elem);
751
+ var name;
752
+ var form;
753
+ var ret = emptyJ;
754
+ if(elem[0].type == 'radio'){
755
+ form = elem.prop('form');
756
+ name = elem[0].name;
757
+ if(!name){
758
+ ret = elem;
759
+ } else if(form){
760
+ ret = $(form[name]);
761
+ } else {
762
+ ret = $(document.getElementsByName(name)).filter(function(){
763
+ return !$.prop(this, 'form');
764
+ });
765
+ }
766
+ ret = ret.filter('[type="radio"]');
767
+ }
768
+ return ret;
769
+ };
770
+ //submitbubbles for IE6-IE8
771
+ var supportSubmitBubbles = !('submitBubbles' in $.support) || $.support.submitBubbles;
772
+ var addSubmitBubbles = function(form){
773
+ if (!supportSubmitBubbles && form && typeof form == 'object' && !form._submit_attached ) {
774
+
775
+ $.event.add( form, 'submit._submit', function( event ) {
776
+ event._submit_bubble = true;
777
+ });
778
+
779
+ form._submit_attached = true;
780
+ }
781
+ };
782
+ if(!supportSubmitBubbles && $.event.special.submit){
783
+
784
+ $.event.special.submit.setup = function() {
785
+ // Only need this for delegated form submit events
786
+ if ( $.nodeName( this, "form" ) ) {
787
+ return false;
788
+ }
789
+
790
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
791
+ $.event.add( this, "click._submit keypress._submit", function( e ) {
792
+ // Node name check avoids a VML-related crash in IE (#9807)
793
+ var elem = e.target,
794
+ form = $.nodeName( elem, 'input' ) || $.nodeName( elem, 'button' ) ? $.prop(elem, 'form') : undefined;
795
+ addSubmitBubbles(form);
564
796
 
565
- if(errorBox && errorBox.jquery){
566
- fieldWrapper.removeClass(invalidWrapperClass);
567
- errorBox.message = '';
568
- $(elem).filter('input').off('.recheckinvalid');
569
- errorBox[fx[options.iVal.fx].hide](function(){
570
- $(this).attr({hidden: 'hidden'});
797
+ });
798
+ // return undefined since we don't need an event listener
799
+ };
800
+ }
801
+
802
+
803
+
804
+ webshims.defineNodeNamesBooleanProperty(['input', 'textarea', 'select'], 'required', {
805
+ set: function(value){
806
+ $(this).getShadowFocusElement().attr('aria-required', !!(value)+'');
807
+ },
808
+ initAttr: Modernizr.localstorage //only if we have aria-support
809
+ });
810
+
811
+ webshims.reflectProperties(['input'], ['pattern']);
812
+
813
+
814
+ if( !('maxLength' in document.createElement('textarea')) ){
815
+ var constrainMaxLength = (function(){
816
+ var timer;
817
+ var curLength = 0;
818
+ var lastElement = $([]);
819
+ var max = 1e9;
820
+ var constrainLength = function(){
821
+ var nowValue = lastElement.prop('value');
822
+ var nowLen = nowValue.length;
823
+ if(nowLen > curLength && nowLen > max){
824
+ nowLen = Math.max(curLength, max);
825
+ lastElement.prop('value', nowValue.substr(0, nowLen ));
826
+ }
827
+ curLength = nowLen;
828
+ };
829
+ var remove = function(){
830
+ clearTimeout(timer);
831
+ lastElement.unbind('.maxlengthconstraint');
832
+ };
833
+ return function(element, maxLength){
834
+ remove();
835
+ if(maxLength > -1){
836
+ max = maxLength;
837
+ curLength = $.prop(element, 'value').length;
838
+ lastElement = $(element);
839
+ lastElement.on({
840
+ 'keydown.maxlengthconstraint keypress.maxlengthconstraint paste.maxlengthconstraint cut.maxlengthconstraint': function(e){
841
+ setTimeout(constrainLength, 0);
842
+ },
843
+ 'keyup.maxlengthconstraint': constrainLength,
844
+ 'blur.maxlengthconstraint': remove
571
845
  });
846
+ timer = setInterval(constrainLength, 200);
572
847
  }
573
- if(!reset){
574
- this.addSuccess(elem, fieldWrapper);
848
+ };
849
+ })();
850
+
851
+ constrainMaxLength.update = function(element, maxLength){
852
+ if($(element).is(':focus')){
853
+ if(!maxLength){
854
+ maxLength = $.prop(element, 'maxlength');
575
855
  }
576
- return fieldWrapper;
577
- },
578
- recheckInvalidInput: function(input){
579
- if(options.iVal.recheckDelay && options.iVal.recheckDelay > 90){
580
- var timer;
581
- var throttle = function(){
582
- switchValidityClass({type: 'input', target: input});
583
- };
584
- $(input)
585
- .filter('input:not([type="checkbox"], [type="radio"])')
586
- .off('.recheckinvalid')
587
- .on('input.recheckinvalid', function(){
588
- clearTimeout(timer);
589
- timer = setTimeout(throttle, options.iVal.recheckDelay);
590
- })
591
- .on('focusout.recheckinvalid', function(){
592
- clearTimeout(timer);
593
- })
594
- ;
856
+ constrainMaxLength(element, maxLength);
857
+ }
858
+ };
859
+
860
+ $(document).on('focusin', function(e){
861
+ var maxLength;
862
+ if(e.target.nodeName == "TEXTAREA" && (maxLength = $.prop(e.target, 'maxlength')) > -1){
863
+ constrainMaxLength(e.target, maxLength);
864
+ }
865
+ });
866
+
867
+ webshims.defineNodeNameProperty('textarea', 'maxlength', {
868
+ attr: {
869
+ set: function(val){
870
+ this.setAttribute('maxlength', ''+val);
871
+ constrainMaxLength.update(this);
872
+ },
873
+ get: function(){
874
+ var ret = this.getAttribute('maxlength');
875
+ return ret == null ? undefined : ret;
595
876
  }
596
877
  },
597
- showError: function(elem){
598
- var fieldWrapper = this.getFieldWrapper(elem);
599
- var box = this.get(elem, fieldWrapper);
600
- var message = $(elem).getErrorMessage();
601
- if(box.message != message){
602
- box.stop(true, true).html('<p>'+ message +'</p>');
603
- box.message = message;
604
- fieldWrapper.addClass(invalidWrapperClass).removeClass(successWrapperClass);
605
- if(box.is('[hidden]') || box.css('display') == 'none'){
606
- this.recheckInvalidInput(elem);
607
- box
608
- .css({display: 'none'})
609
- .removeAttr('hidden')
610
- [fx[options.iVal.fx].show]()
611
- ;
878
+ prop: {
879
+ set: function(val){
880
+ if(isNumber(val)){
881
+ if(val < 0){
882
+ throw('INDEX_SIZE_ERR');
883
+ }
884
+ val = parseInt(val, 10);
885
+ this.setAttribute('maxlength', val);
886
+ constrainMaxLength.update(this, val);
887
+ return;
612
888
  }
889
+ this.setAttribute('maxlength', '0');
890
+ constrainMaxLength.update(this, 0);
891
+ },
892
+ get: function(){
893
+ var val = this.getAttribute('maxlength');
894
+ return (isNumber(val) && val >= 0) ? parseInt(val, 10) : -1;
895
+
613
896
  }
614
- fieldWrapper.removeClass(successWrapperClass);
615
- $(elem).off('.recheckvalid');
616
-
617
- return fieldWrapper;
618
- },
619
- reset: function(elem){
620
- this.hideError(elem, true).removeClass(successWrapperClass);
621
- },
622
- toggle: function(elem){
623
- if($(elem).is(':invalid')){
624
- this.showError(elem);
625
- } else {
626
- this.hideError(elem);
897
+ }
898
+ });
899
+ webshims.defineNodeNameProperty('textarea', 'maxLength', {
900
+ prop: {
901
+ set: function(val){
902
+ $.prop(this, 'maxlength', val);
903
+ },
904
+ get: function(){
905
+ return $.prop(this, 'maxlength');
627
906
  }
628
907
  }
629
- };
630
-
631
- $(document.body)
632
- .on({
633
- 'changedvaliditystate': function(e){
634
- if(options.iVal.sel){
635
- var form = $(e.target).jProp('form');
636
- if(form.is(options.iVal.sel)){
637
- webshims.errorbox.toggle(e.target);
638
- }
639
- }
908
+ });
909
+ }
910
+
911
+ if(!$.support.getSetAttribute && $('<form novalidate></form>').attr('novalidate') == null){
912
+ webshims.defineNodeNameProperty('form', 'novalidate', {
913
+ attr: {
914
+ set: function(val){
915
+ this.setAttribute('novalidate', ''+val);
640
916
  },
641
- resetvalidityui: function(e){
642
- if (options.iVal.sel) {
643
- var form = $(e.target).jProp('form');
644
- if (form.is(options.iVal.sel)) {
645
- webshims.errorbox.reset(e.target);
917
+ get: function(){
918
+ var ret = this.getAttribute('novalidate');
919
+ return ret == null ? undefined : ret;
920
+ }
921
+ }
922
+ });
923
+ }
924
+
925
+
926
+ if(Modernizr.formattribute === false || !Modernizr.fieldsetdisabled){
927
+ (function(){
928
+
929
+ (function(prop, undefined){
930
+ $.prop = function(elem, name, value){
931
+ var ret;
932
+ if(elem && elem.nodeType == 1 && value === undefined && $.nodeName(elem, 'form') && elem.id){
933
+ ret = document.getElementsByName(name);
934
+ if(!ret || !ret.length){
935
+ ret = document.getElementById(name);
646
936
  }
647
- }
648
- },
649
- firstinvalid: function(e){
650
- if(options.iVal.sel && options.iVal.handleBubble){
651
- var form = $(e.target).jProp('form');
652
- if(form.is(options.iVal.sel)){
653
- e.preventDefault();
654
- if(options.iVal.handleBubble != 'none'){
655
- webshims.validityAlert.showFor( e.target, false, false, options.iVal.handleBubble == 'hide' );
937
+ if(ret){
938
+ ret = $(ret).filter(function(){
939
+ return $.prop(this, 'form') == elem;
940
+ }).get();
941
+ if(ret.length){
942
+ return ret.length == 1 ? ret[0] : ret;
656
943
  }
657
944
  }
658
945
  }
659
- },
660
- submit: function(e){
661
- if(options.iVal.sel && !options.iVal.noSubmitCheck &&$(e.target).is(options.iVal.sel) && $.prop(e.target, 'noValidate') && !$(e.target).checkValidity()){
662
- e.stopImmediatePropagation();
663
- return false;
664
- }
946
+ return prop.apply(this, arguments);
947
+ };
948
+ })($.prop, undefined);
949
+
950
+ var removeAddedElements = function(form){
951
+ var elements = $.data(form, 'webshimsAddedElements');
952
+ if(elements){
953
+ elements.remove();
954
+ $.removeData(form, 'webshimsAddedElements');
665
955
  }
666
- })
667
- ;
668
-
669
- webshims.modules["form-core"].getGroupElements = getGroupElements;
670
-
671
-
672
- if(options.replaceValidationUI){
673
- webshims.ready('DOM forms', function(){
674
- $(document).on('firstinvalid', function(e){
675
- if(!e.isInvalidUIPrevented()){
676
- e.preventDefault();
677
- webshims.validityAlert.showFor( e.target );
956
+ };
957
+
958
+
959
+ if(!Modernizr.formattribute){
960
+ webshims.defineNodeNamesProperty(['input', 'textarea', 'select', 'button', 'fieldset'], 'form', {
961
+ prop: {
962
+ get: function(){
963
+ var form = webshims.contentAttr(this, 'form');
964
+ if(form){
965
+ form = document.getElementById(form);
966
+ if(form && !$.nodeName(form, 'form')){
967
+ form = null;
968
+ }
969
+ }
970
+ return form || this.form;
971
+ },
972
+ writeable: false
678
973
  }
679
974
  });
680
- });
681
- }
682
-
683
- /* extension, but also used to fix native implementation workaround/bugfixes */
684
- (function(){
685
- var firstEvent,
686
- invalids = [],
687
- stopSubmitTimer,
688
- form
689
- ;
975
+
976
+
977
+ webshims.defineNodeNamesProperty(['form'], 'elements', {
978
+ prop: {
979
+ get: function(){
980
+ var id = this.id;
981
+ var elements = $.makeArray(this.elements);
982
+ if(id){
983
+ elements = $(elements).add('input[form="'+ id +'"], select[form="'+ id +'"], textarea[form="'+ id +'"], button[form="'+ id +'"], fieldset[form="'+ id +'"]').not('.webshims-visual-hide > *').get();
984
+ }
985
+ return elements;
986
+ },
987
+ writeable: false
988
+ }
989
+ });
990
+
991
+
992
+
993
+ $(function(){
994
+ var stopPropagation = function(e){
995
+ e.stopPropagation();
996
+ };
997
+ var submitters = {
998
+ image: 1,
999
+ submit: 1
1000
+ };
1001
+ $(document).on('submit', function(e){
1002
+
1003
+ if(!e.isDefaultPrevented()){
1004
+ var form = e.target;
1005
+ var id = form.id;
1006
+ var elements;
1007
+
1008
+
1009
+ if(id){
1010
+ removeAddedElements(form);
1011
+
1012
+ elements = $('input[form="'+ id +'"], select[form="'+ id +'"], textarea[form="'+ id +'"]')
1013
+ .filter(function(){
1014
+ return !this.disabled && this.name && this.form != form;
1015
+ })
1016
+ .clone()
1017
+ ;
1018
+ if(elements.length){
1019
+ $.data(form, 'webshimsAddedElements', $('<div class="webshims-visual-hide" />').append(elements).appendTo(form));
1020
+ setTimeout(function(){
1021
+ removeAddedElements(form);
1022
+ }, 9);
1023
+ }
1024
+ elements = null;
1025
+ }
1026
+ }
1027
+ });
1028
+
1029
+
1030
+ $(document).on('click', function(e){
1031
+ if(submitters[e.target.type] && !e.isDefaultPrevented() && $(e.target).is('input[form], button[form]')){
1032
+ var trueForm = $.prop(e.target, 'form');
1033
+ var formIn = e.target.form;
1034
+ var clone;
1035
+ if(trueForm && trueForm != formIn){
1036
+ clone = $(e.target)
1037
+ .clone()
1038
+ .removeAttr('form')
1039
+ .addClass('webshims-visual-hide')
1040
+ .on('click', stopPropagation)
1041
+ .appendTo(trueForm)
1042
+ ;
1043
+ if(formIn){
1044
+ e.preventDefault();
1045
+ }
1046
+ addSubmitBubbles(trueForm);
1047
+ clone.trigger('click');
1048
+ setTimeout(function(){
1049
+ clone.remove();
1050
+ clone = null;
1051
+ }, 9);
1052
+ }
1053
+ }
1054
+ });
1055
+ });
1056
+ }
1057
+
1058
+ if(!Modernizr.fieldsetdisabled){
1059
+ webshims.defineNodeNamesProperty(['fieldset'], 'elements', {
1060
+ prop: {
1061
+ get: function(){
1062
+ //add listed elements without keygen, object, output
1063
+ return $('input, select, textarea, button, fieldset', this).get() || [];
1064
+ },
1065
+ writeable: false
1066
+ }
1067
+ });
1068
+ }
690
1069
 
691
- $(document).on('invalid', function(e){
692
- if(e.wrongWebkitInvalid){return;}
693
- var jElm = $(e.target);
694
-
1070
+ if(!$.fn.finish && parseFloat($.fn.jquery, 10) < 1.9){
1071
+ var rCRLF = /\r?\n/g,
1072
+ rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
1073
+ rselectTextarea = /^(?:select|textarea)/i;
1074
+ $.fn.serializeArray = function() {
1075
+ return this.map(function(){
1076
+ var elements = $.prop(this, 'elements');
1077
+ return elements ? $.makeArray( elements ) : this;
1078
+ })
1079
+ .filter(function(){
1080
+ return this.name && !this.disabled &&
1081
+ ( this.checked || rselectTextarea.test( this.nodeName ) ||
1082
+ rinput.test( this.type ) );
1083
+ })
1084
+ .map(function( i, elem ){
1085
+ var val = $( this ).val();
695
1086
 
696
- if(!firstEvent){
697
- //trigger firstinvalid
698
- firstEvent = $.Event('firstinvalid');
699
- firstEvent.isInvalidUIPrevented = e.isDefaultPrevented;
700
- var firstSystemInvalid = $.Event('firstinvalidsystem');
701
- $(document).triggerHandler(firstSystemInvalid, {element: e.target, form: e.target.form, isInvalidUIPrevented: e.isDefaultPrevented});
702
- jElm.trigger(firstEvent);
703
- }
1087
+ return val == null ?
1088
+ null :
1089
+ $.isArray( val ) ?
1090
+ $.map( val, function( val, i ){
1091
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
1092
+ }) :
1093
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
1094
+ }).get();
1095
+ };
1096
+ }
1097
+
1098
+ })();
1099
+ }
704
1100
 
705
- //if firstinvalid was prevented all invalids will be also prevented
706
- if( firstEvent && firstEvent.isDefaultPrevented() ){
707
- e.preventDefault();
1101
+ if($('<input />').prop('labels') == null){
1102
+ webshims.defineNodeNamesProperty('button, input, keygen, meter, output, progress, select, textarea', 'labels', {
1103
+ prop: {
1104
+ get: function(){
1105
+ if(this.type == 'hidden'){return null;}
1106
+ var id = this.id;
1107
+ var labels = $(this)
1108
+ .closest('label')
1109
+ .filter(function(){
1110
+ var hFor = (this.attributes['for'] || {});
1111
+ return (!hFor.specified || hFor.value == id);
1112
+ })
1113
+ ;
1114
+
1115
+ if(id) {
1116
+ labels = labels.add('label[for="'+ id +'"]');
1117
+ }
1118
+ return labels.get();
1119
+ },
1120
+ writeable: false
708
1121
  }
709
- invalids.push(e.target);
710
- e.extraData = 'fix';
711
- clearTimeout(stopSubmitTimer);
712
- stopSubmitTimer = setTimeout(function(){
713
- var lastEvent = {type: 'lastinvalid', cancelable: false, invalidlist: $(invalids)};
714
- //reset firstinvalid
715
- firstEvent = false;
716
- invalids = [];
717
- $(e.target).trigger(lastEvent, [lastEvent]);
718
- }, 9);
719
- jElm = null;
720
1122
  });
721
- })();
1123
+ }
722
1124
 
723
- //see: https://bugs.webkit.org/show_bug.cgi?id=113377
724
- if (chromeBugs && webkitVersion < 540) {
1125
+ if(!('value' in document.createElement('progress'))){
725
1126
  (function(){
726
- var elems = /^(?:textarea|input)$/i;
727
- var form = false;
728
1127
 
729
- document.addEventListener('contextmenu', function(e){
730
- if (elems.test(e.target.nodeName || '') && (form = e.target.form)) {
731
- setTimeout(function(){
732
- form = false;
733
- }, 1);
734
- }
735
- }, false);
1128
+ var nan = parseInt('NaN', 10);
736
1129
 
737
- $(window).on('invalid', function(e){
738
- if (e.originalEvent && form && form == e.target.form) {
739
- e.wrongWebkitInvalid = true;
740
- e.stopImmediatePropagation();
1130
+ var updateProgress = function(progress){
1131
+ var position;
1132
+
1133
+
1134
+ position = $.prop(progress, 'position');
1135
+
1136
+ $.attr(progress, 'data-position', position);
1137
+ $('> span', progress).css({width: (position < 0 ? 100 : position * 100) +'%'});
1138
+ };
1139
+ var desc = {
1140
+ position: {
1141
+ prop: {
1142
+ get: function(){
1143
+ var max;
1144
+ //jQuery 1.8.x try's to normalize "0" to 0
1145
+ var val = this.getAttribute('value');
1146
+ var ret = -1;
1147
+
1148
+ val = val ? (val * 1) : nan;
1149
+ if(!isNaN(val)){
1150
+ max = $.prop(this, 'max');
1151
+ ret = Math.max(Math.min(val / max, 1), 0);
1152
+ if(updateProgress.isInChange){
1153
+ $.attr(this, 'aria-valuenow', ret * 100);
1154
+ if(updateProgress.isInChange == 'max'){
1155
+ $.attr(this, 'aria-valuemax', max);
1156
+ }
1157
+ }
1158
+ } else if(updateProgress.isInChange) {
1159
+ $(this).removeAttr('aria-valuenow');
1160
+ }
1161
+ return ret;
1162
+ },
1163
+ writeable: false
1164
+ }
741
1165
  }
1166
+ };
1167
+
1168
+ $.each({value: 0, max: 1}, function(name, defValue){
1169
+ var removeProp = (name == 'value' && !$.fn.finish);
1170
+ desc[name] = {
1171
+ attr: {
1172
+ set: function(value){
1173
+ var ret = desc[name].attr._supset.call(this, value);
1174
+ updateProgress.isInChange = name;
1175
+ updateProgress(this);
1176
+ updateProgress.isInChange = false;
1177
+ return ret;
1178
+ }
1179
+ },
1180
+ removeAttr: {
1181
+ value: function(){
1182
+ this.removeAttribute(name);
1183
+ if(removeProp){
1184
+ try {
1185
+ delete this.value;
1186
+ } catch(er){}
1187
+ }
1188
+ updateProgress.isInChange = name;
1189
+ updateProgress(this);
1190
+ updateProgress.isInChange = false;
1191
+ }
1192
+ },
1193
+ prop: {
1194
+ get: function(){
1195
+ var max;
1196
+ var ret = (desc[name].attr.get.call(this) * 1);
1197
+ if(ret < 0 || isNaN(ret)){
1198
+ ret = defValue;
1199
+ } else if(name == 'value'){
1200
+ ret = Math.min(ret, $.prop(this, 'max'));
1201
+ } else if(ret === 0){
1202
+ ret = defValue;
1203
+ }
1204
+ return ret;
1205
+ },
1206
+ set: function(value){
1207
+ value = value * 1;
1208
+ if(isNaN(value)){
1209
+ webshims.error('Floating-point value is not finite.');
1210
+ }
1211
+ return desc[name].attr.set.call(this, value);
1212
+ }
1213
+ }
1214
+ };
742
1215
  });
743
1216
 
1217
+ webshims.createElement(
1218
+ 'progress',
1219
+ function(){
1220
+ var labels = $(this)
1221
+ .attr({role: 'progressbar', 'aria-valuemin': '0'})
1222
+ .html('<span class="progress-value" />')
1223
+ .jProp('labels')
1224
+ .map(function(){
1225
+ return webshims.getID(this);
1226
+ })
1227
+ .get()
1228
+ ;
1229
+ if(labels.length){
1230
+ $.attr(this, 'aria-labelledby', labels.join(' '));
1231
+ } else {
1232
+ webshims.info("you should use label elements for your prgogress elements");
1233
+ }
1234
+
1235
+ updateProgress.isInChange = 'max';
1236
+ updateProgress(this);
1237
+ updateProgress.isInChange = false;
1238
+ },
1239
+ desc
1240
+ );
1241
+
744
1242
  })();
745
1243
  }
746
- });
747
1244
 
748
- webshims.register('form-validators', function($, webshims, window, document, undefined, options){
749
- "use strict";
750
-
751
- (function(){
752
- if(webshims.refreshCustomValidityRules){
753
- webshims.error("form-validators already included. please remove custom-validity.js");
754
- }
755
-
756
- var customValidityRules = {};
757
- var formReady = false;
758
- var blockCustom;
759
- var initTest;
760
- var onEventTest = function(e){
761
- webshims.refreshCustomValidityRules(e.target);
762
- };
763
- var noValidate = function(){
764
- return !noValidate.types[this.type];
765
- };
766
- noValidate.types = {
767
- hidden: 1,
768
- image: 1,
769
- button: 1,
770
- reset: 1,
771
- submit: 1
772
- };
773
-
774
- webshims.customErrorMessages = {};
775
- webshims.addCustomValidityRule = function(name, test, defaultMessage){
776
- customValidityRules[name] = test;
777
- if(!webshims.customErrorMessages[name]){
778
- webshims.customErrorMessages[name] = [];
779
- webshims.customErrorMessages[name][''] = defaultMessage || name;
780
- }
781
- if(formReady){
782
- $('input, select, textarea')
783
- .filter(noValidate)
784
- .each(function(){
785
- testValidityRules(this);
786
- })
787
- ;
788
- }
789
- };
790
- webshims.refreshCustomValidityRules = function(elem){
791
- if(!initTest){return;}
792
-
793
- var data = $(elem).data() || $.data(elem, {});
794
- var customMismatchedRule = data.customMismatchedRule;
795
- var validity = $.prop(elem, 'validity') || {};
796
- var message = '';
797
- var setMessage = function(message, errorType){
798
- blockCustom = true;
799
- data.customMismatchedRule = message ? errorType : '';
800
-
801
- if(typeof message != 'string'){
802
- message = $(elem).data('errormessage') || elem.getAttribute('x-moz-errormessage') || webshims.customErrorMessages[errorType][webshims.activeLang()] || webshims.customErrorMessages[errorType][''];
1245
+ try {
1246
+ document.querySelector(':checked');
1247
+ } catch(er){
1248
+ (function(){
1249
+ $('html').addClass('no-csschecked');
1250
+ var checkInputs = {
1251
+ radio: 1,
1252
+ checkbox: 1
1253
+ };
1254
+ var selectChange = function(){
1255
+ var options = this.options || [];
1256
+ var i, len, option;
1257
+ for(i = 0, len = options.length; i < len; i++){
1258
+ option = $(options[i]);
1259
+ option[$.prop(options[i], 'selected') ? 'addClass' : 'removeClass']('prop-checked');
803
1260
  }
1261
+ };
1262
+ var checkChange = function(){
1263
+ var fn = $.prop(this, 'checked') ? 'addClass' : 'removeClass';
1264
+ var className = this.className || '';
1265
+ var parent;
804
1266
 
805
- if(typeof message == 'object'){
806
- message = message[errorType] || message.customError || message.defaultMessage;
1267
+ //IE8- has problems to update styles, we help
1268
+ if( (className.indexOf('prop-checked') == -1) == (fn == 'addClass')){
1269
+ $(this)[fn]('prop-checked');
1270
+ if((parent = this.parentNode)){
1271
+ parent.className = parent.className;
1272
+ }
807
1273
  }
808
- $(elem).setCustomValidity(message);
809
- blockCustom = false;
810
1274
  };
811
- if(customMismatchedRule || validity.valid || (data.dependentValidation && !data.dependentValidation._init)){
812
- var val = $(elem).val();
813
- $.each(customValidityRules, function(name, test){
814
- message = test(elem, val, data, setMessage) || '';
815
- customMismatchedRule = name;
816
- if(message){
817
- return false;
818
- }
819
- });
820
- if(message != 'async'){
821
- setMessage(message, customMismatchedRule);
1275
+
1276
+
1277
+ webshims.onNodeNamesPropertyModify('select', 'value', selectChange);
1278
+ webshims.onNodeNamesPropertyModify('select', 'selectedIndex', selectChange);
1279
+ webshims.onNodeNamesPropertyModify('option', 'selected', function(){
1280
+ $(this).closest('select').each(selectChange);
1281
+ });
1282
+ webshims.onNodeNamesPropertyModify('input', 'checked', function(value, boolVal){
1283
+ var type = this.type;
1284
+ if(type == 'radio' && boolVal){
1285
+ getGroupElements(this).each(checkChange);
1286
+ } else if(checkInputs[type]) {
1287
+ $(this).each(checkChange);
822
1288
  }
823
- }
824
- return message;
825
- };
826
- var testValidityRules = webshims.refreshCustomValidityRules;
827
-
828
- webshims.ready('forms form-validation', function(){
1289
+ });
829
1290
 
830
- $.propHooks.setCustomValidity = {
831
- get: function(elem){
832
- if(!blockCustom){
833
- $.data(elem, 'customMismatchedRule', '');
1291
+ $(document).on('change', function(e){
1292
+
1293
+ if(checkInputs[e.target.type]){
1294
+ if(e.target.type == 'radio'){
1295
+ getGroupElements(e.target).each(checkChange);
1296
+ } else {
1297
+ $(e.target)[$.prop(e.target, 'checked') ? 'addClass' : 'removeClass']('prop-checked');
834
1298
  }
835
- return null;
1299
+ } else if(e.target.nodeName.toLowerCase() == 'select'){
1300
+ $(e.target).each(selectChange);
836
1301
  }
837
- };
838
-
839
-
840
- setTimeout(function(){
841
- webshims.addReady(function(context, selfElement){
842
- initTest = true;
843
- $('input, select, textarea', context).add(selfElement.filter('input, select, textarea'))
844
- .filter(noValidate)
845
- .each(function(){
846
- testValidityRules(this);
847
- })
848
- ;
849
-
850
- formReady = true;
851
- });
852
- $(document).on('refreshCustomValidityRules', onEventTest);
853
- }, 9);
1302
+ });
854
1303
 
855
- });
856
-
857
- })();
858
-
859
- /*
860
- * adds support for HTML5 constraint validation
861
- * - partial pattern: <input data-partial-pattern="RegExp" />
862
- * - creditcard-validation: <input class="creditcard-input" />
863
- * - several dependent-validation patterns (examples):
864
- * - <input type="email" id="mail" /> <input data-dependent-validation='mail' />
865
- * - <input type="date" id="start" data-dependent-validation='{"from": "end", "prop": "max"}' /> <input type="date" id="end" data-dependent-validation='{"from": "start", "prop": "min"}' />
866
- * - <input type="checkbox" id="check" /> <input data-dependent-validation='checkbox' />
867
- */
868
- (function(){
869
-
870
- var addCustomValidityRule = webshims.addCustomValidityRule;
871
- var getId = function(name){
872
- return document.getElementById(name);
873
- };
874
- addCustomValidityRule('partialPattern', function(elem, val, pattern){
875
- pattern = pattern.partialPattern;
876
- if(!val || !pattern){return;}
877
- return !(new RegExp('(' + pattern + ')', 'i').test(val));
878
- }, 'This format is not allowed here.');
879
-
880
-
881
- addCustomValidityRule('tooShort', function(elem, val, data){
882
- if(!val || !data.minlength){return;}
883
- return data.minlength > val.length;
884
- }, 'Entered value is too short.');
885
-
886
- var groupTimer = {};
887
- addCustomValidityRule('group-required', function(elem, val){
888
- var name = elem.name;
889
- if(!name || elem.type !== 'checkbox' || !$(elem).hasClass('group-required')){return;}
890
- var checkboxes = $( (elem.form && elem.form[name]) || document.getElementsByName(name));
891
- var isValid = checkboxes.filter(':checked:enabled');
892
- if(groupTimer[name]){
893
- clearTimeout(groupTimer[name]);
894
- }
895
- groupTimer[name] = setTimeout(function(){
896
- checkboxes
897
- .addClass('group-required')
898
- .unbind('click.groupRequired')
899
- .bind('click.groupRequired', function(){
900
- checkboxes.filter('.group-required').each(function(){
901
- webshims.refreshCustomValidityRules(this);
902
- });
1304
+ webshims.addReady(function(context, contextElem){
1305
+ $('option, input', context)
1306
+ .add(contextElem.filter('option, input'))
1307
+ .each(function(){
1308
+ var prop;
1309
+ if(checkInputs[this.type]){
1310
+ prop = 'checked';
1311
+ } else if(this.nodeName.toLowerCase() == 'option'){
1312
+ prop = 'selected';
1313
+ }
1314
+ if(prop){
1315
+ $(this)[$.prop(this, prop) ? 'addClass' : 'removeClass']('prop-checked');
1316
+ }
1317
+
903
1318
  })
904
1319
  ;
905
- }, 9);
1320
+ });
1321
+ })();
1322
+ }
1323
+
1324
+ (function(){
1325
+ var bustedPlaceholder;
1326
+ Modernizr.textareaPlaceholder = !!('placeholder' in $('<textarea />')[0]);
1327
+ if(Modernizr.input.placeholder && options.overridePlaceholder){
1328
+ bustedPlaceholder = true;
1329
+ }
1330
+ if(Modernizr.input.placeholder && Modernizr.textareaPlaceholder && !bustedPlaceholder){
1331
+ (function(){
1332
+ var ua = navigator.userAgent;
1333
+
1334
+ if(ua.indexOf('Mobile') != -1 && ua.indexOf('Safari') != -1){
1335
+ $(window).on('orientationchange', (function(){
1336
+ var timer;
1337
+ var retVal = function(i, value){
1338
+ return value;
1339
+ };
1340
+
1341
+ var set = function(){
1342
+ $('input[placeholder], textarea[placeholder]').attr('placeholder', retVal);
1343
+ };
1344
+ return function(e){
1345
+ clearTimeout(timer);
1346
+ timer = setTimeout(set, 9);
1347
+ };
1348
+ })());
1349
+ }
1350
+ })();
906
1351
 
907
- return !(isValid[0]);
908
- }, 'Please check one of these checkboxes.');
909
-
910
- // based on https://sites.google.com/site/abapexamples/javascript/luhn-validation
911
- addCustomValidityRule('creditcard', function(elem, value){
912
- if(!value || !$(elem).hasClass('creditcard-input')){return;}
913
- value = value.replace(/\-/g, "");
914
- //if it's not numeric return true >- for invalid
915
- if(value != value * 1){return true;}
916
- var len = value.length;
917
- var sum = 0;
918
- var mul = 1;
919
- var ca;
920
-
921
- while (len--) {
922
- ca = parseInt(value.charAt(len),10) * mul;
923
- sum += ca - (ca>9)*9;// sum += ca - (-(ca>9))|9
924
- // 1 <--> 2 toggle.
925
- mul ^= 3; // (mul = 3 - mul);
926
- }
927
- return !((sum%10 === 0) && (sum > 0));
928
- }, 'Please enter a valid credit card number');
1352
+ //abort
1353
+ return;
1354
+ }
929
1355
 
930
- var dependentDefaults = {
931
- //"from": "IDREF || UniqueNAMEREF", //required property: element
932
- "prop": "value", //default: value||disabled (last if "from-prop" is checked)
933
- "from-prop": "value", //default: value||checked (last if element checkbox or radio)
934
- "toggle": false
935
- };
1356
+ var isOver = (webshims.cfg.forms.placeholderType == 'over');
1357
+ var isResponsive = (webshims.cfg.forms.responsivePlaceholder);
1358
+ var polyfillElements = ['textarea'];
1359
+ var debug = webshims.debug !== false;
1360
+ if(!Modernizr.input.placeholder || bustedPlaceholder){
1361
+ polyfillElements.push('input');
1362
+ }
936
1363
 
937
- var getGroupElements = function(elem) {
938
- return $(elem.form[elem.name]).filter('[type="radio"]');
1364
+ var setSelection = function(elem){
1365
+ try {
1366
+ if(elem.setSelectionRange){
1367
+ elem.setSelectionRange(0, 0);
1368
+ return true;
1369
+ } else if(elem.createTextRange){
1370
+ var range = elem.createTextRange();
1371
+ range.collapse(true);
1372
+ range.moveEnd('character', 0);
1373
+ range.moveStart('character', 0);
1374
+ range.select();
1375
+ return true;
1376
+ }
1377
+ } catch(er){}
939
1378
  };
940
- webshims.ready('form-validation', function(){
941
- if(webshims.modules){
942
- getGroupElements = webshims.modules["form-core"].getGroupElements || getGroupElements;
943
- }
944
- });
945
1379
 
946
- addCustomValidityRule('dependent', function(elem, val, data){
947
- data = data.dependentValidation;
948
- if( !data ){return;}
949
- var specialVal;
950
- var depFn = function(e){
951
- var val = $.prop(data.masterElement, data["from-prop"]);
952
- if(specialVal){
953
- val = $.inArray(val, specialVal) !== -1;
1380
+ var hidePlaceholder = function(elem, data, value, _onFocus){
1381
+ if(value === false){
1382
+ value = $.prop(elem, 'value');
954
1383
  }
955
- if(data.toggle){
956
- val = !val;
1384
+
1385
+ if(!isOver && elem.type != 'password'){
1386
+ if(!value && _onFocus && setSelection(elem)){
1387
+ var selectTimer = setTimeout(function(){
1388
+ setSelection(elem);
1389
+ }, 9);
1390
+ $(elem)
1391
+ .off('.placeholderremove')
1392
+ .on({
1393
+ 'keydown.placeholderremove keypress.placeholderremove paste.placeholderremove input.placeholderremove': function(e){
1394
+ if(e && (e.keyCode == 17 || e.keyCode == 16)){return;}
1395
+ elem.value = $.prop(elem, 'value');
1396
+ data.box.removeClass('placeholder-visible');
1397
+ clearTimeout(selectTimer);
1398
+ $(elem).unbind('.placeholderremove');
1399
+ },
1400
+ 'mousedown.placeholderremove drag.placeholderremove select.placeholderremove': function(e){
1401
+ setSelection(elem);
1402
+ clearTimeout(selectTimer);
1403
+ selectTimer = setTimeout(function(){
1404
+ setSelection(elem);
1405
+ }, 9);
1406
+ },
1407
+ 'blur.placeholderremove': function(){
1408
+ clearTimeout(selectTimer);
1409
+ $(elem).unbind('.placeholderremove');
1410
+ }
1411
+ })
1412
+ ;
1413
+ return;
1414
+ } else if(!_onFocus && !value && elem.value){ //especially on submit
1415
+ elem.value = value;
1416
+ }
1417
+ } else if(!value && _onFocus){
1418
+ $(elem)
1419
+ .off('.placeholderremove')
1420
+ .on({
1421
+ 'keydown.placeholderremove keypress.placeholderremove paste.placeholderremove input.placeholderremove': function(e){
1422
+ if(e && (e.keyCode == 17 || e.keyCode == 16)){return;}
1423
+ data.box.removeClass('placeholder-visible');
1424
+ $(elem).unbind('.placeholderremove');
1425
+ },
1426
+ 'blur.placeholderremove': function(){
1427
+ $(elem).unbind('.placeholderremove');
1428
+ }
1429
+ })
1430
+ ;
1431
+ return;
957
1432
  }
958
- $.prop( elem, data.prop, val);
959
- if(e){
960
- $(elem).getShadowElement().filter('.user-error, .user-success').trigger('refreshvalidityui');
1433
+ data.box.removeClass('placeholder-visible');
1434
+ },
1435
+ showPlaceholder = function(elem, data, placeholderTxt){
1436
+ if(placeholderTxt === false){
1437
+ placeholderTxt = $.prop(elem, 'placeholder');
961
1438
  }
962
- };
963
-
964
- if(!data._init || !data.masterElement){
965
1439
 
966
- if(typeof data == 'string'){
967
- data = {"from": data};
1440
+ if(!isOver && elem.type != 'password'){
1441
+ elem.value = placeholderTxt;
1442
+ }
1443
+ data.box.addClass('placeholder-visible');
1444
+ },
1445
+ changePlaceholderVisibility = function(elem, value, placeholderTxt, data, type){
1446
+ if(!data){
1447
+ data = $.data(elem, 'placeHolder');
1448
+ if(!data){return;}
1449
+ }
1450
+ var isVisible = $(elem).hasClass('placeholder-visible');
1451
+ if(placeholderTxt === false){
1452
+ placeholderTxt = $.attr(elem, 'placeholder') || '';
968
1453
  }
969
1454
 
1455
+ $(elem).unbind('.placeholderremove');
970
1456
 
971
- data.masterElement = document.getElementById(data["from"]) || (document.getElementsByName(data["from"] || [])[0]);
972
-
973
- if (!data.masterElement || !data.masterElement.form) {return;}
1457
+ if(value === false){
1458
+ value = $.prop(elem, 'value');
1459
+ }
974
1460
 
975
- if(/radio|checkbox/i.test(data.masterElement.type)){
976
- if(!data["from-prop"]){
977
- data["from-prop"] = 'checked';
978
- }
979
- if(!data.prop && data["from-prop"] == 'checked'){
980
- data.prop = 'disabled';
1461
+ if(!value && (type == 'focus' || (!type && $(elem).is(':focus')))){
1462
+ if(elem.type == 'password' || isOver || isVisible){
1463
+ hidePlaceholder(elem, data, '', true);
981
1464
  }
982
- } else if(!data["from-prop"]){
983
- data["from-prop"] = 'value';
1465
+ return;
984
1466
  }
985
1467
 
986
- if(data["from-prop"].indexOf('value:') === 0){
987
- specialVal = data["from-prop"].replace('value:', '').split('||');
988
- data["from-prop"] = 'value';
989
-
1468
+ if(value){
1469
+ hidePlaceholder(elem, data, value);
1470
+ return;
990
1471
  }
991
1472
 
992
- data = $.data(elem, 'dependentValidation', $.extend({_init: true}, dependentDefaults, data));
993
-
994
- if(data.prop !== "value" || specialVal){
995
- $(data.masterElement.type === 'radio' && getGroupElements(data.masterElement) || data.masterElement).bind('change', depFn);
1473
+ if(placeholderTxt && !value){
1474
+ showPlaceholder(elem, data, placeholderTxt);
996
1475
  } else {
997
- $(data.masterElement).bind('change', function(){
998
- webshims.refreshCustomValidityRules(elem);
999
- $(elem).getShadowElement().filter('.user-error, .user-success').trigger('refreshvalidityui');
1000
- });
1476
+ hidePlaceholder(elem, data, value);
1001
1477
  }
1002
- }
1003
-
1004
- if(data.prop == "value" && !specialVal){
1005
- return ($.prop(data.masterElement, 'value') != val);
1006
- } else {
1007
- depFn();
1008
- return '';
1009
- }
1010
-
1011
- }, 'The value of this field does not repeat the value of the other field');
1012
-
1013
-
1014
- if(window.JSON){
1015
- addCustomValidityRule('ajaxvalidate', function(elem, val, data){
1016
- if(!val || !data.ajaxvalidate){return;}
1017
- var opts;
1018
- if(!data.remoteValidate){
1019
- if(typeof data.ajaxvalidate == 'string'){
1020
- data.ajaxvalidate = {url: data.ajaxvalidate, depends: $([])};
1021
- } else {
1022
- data.ajaxvalidate.depends = data.ajaxvalidate.depends ? $(data.ajaxvalidate.depends).map(getId) : $([]);
1478
+ },
1479
+ hasLabel = function(elem){
1480
+ elem = $(elem);
1481
+ return !!(elem.prop('title') || elem.attr('aria-labelledby') || elem.attr('aria-label') || elem.jProp('labels').length);
1482
+ },
1483
+ createPlaceholder = function(elem){
1484
+ elem = $(elem);
1485
+ return $( hasLabel(elem) ? '<span class="placeholder-text"></span>' : '<label for="'+ elem.prop('id') +'" class="placeholder-text"></label>');
1486
+ },
1487
+ pHolder = (function(){
1488
+ var delReg = /\n|\r|\f|\t/g,
1489
+ allowedPlaceholder = {
1490
+ text: 1,
1491
+ search: 1,
1492
+ url: 1,
1493
+ email: 1,
1494
+ password: 1,
1495
+ tel: 1,
1496
+ number: 1
1023
1497
  }
1024
-
1025
- data.ajaxvalidate.depends.on('refreshCustomValidityRules', function(){
1026
- webshims.refreshCustomValidityRules(elem);
1027
- });
1028
-
1029
- opts = data.ajaxvalidate;
1030
-
1031
- var remoteValidate = {
1032
- ajaxLoading: false,
1033
- restartAjax: false,
1034
- message: 'async',
1035
- cache: {},
1036
- update: function(remoteData){
1037
- if(this.ajaxLoading){
1038
- this.restartAjax = remoteData;
1498
+ ;
1499
+ if(webshims.modules["form-number-date-ui"].loaded){
1500
+ delete allowedPlaceholder.number;
1501
+ }
1502
+
1503
+ return {
1504
+ create: function(elem){
1505
+ var data = $.data(elem, 'placeHolder');
1506
+ var form;
1507
+ var responsiveElem;
1508
+ if(data){return data;}
1509
+ data = $.data(elem, 'placeHolder', {});
1510
+
1511
+ $(elem).on('focus.placeholder blur.placeholder', function(e){
1512
+ changePlaceholderVisibility(this, false, false, data, e.type );
1513
+ data.box[e.type == 'focus' ? 'addClass' : 'removeClass']('placeholder-focused');
1514
+ });
1515
+
1516
+ if((form = $.prop(elem, 'form'))){
1517
+ $(elem).onWSOff('reset.placeholder', function(e){
1518
+ setTimeout(function(){
1519
+ changePlaceholderVisibility(elem, false, false, data, e.type );
1520
+ }, 0);
1521
+ }, false, form);
1522
+ }
1523
+
1524
+ if(elem.type == 'password' || isOver){
1525
+ data.text = createPlaceholder(elem);
1526
+ if(isResponsive || $(elem).is('.responsive-width') || (elem.currentStyle || {width: ''}).width.indexOf('%') != -1){
1527
+ responsiveElem = true;
1528
+ data.box = data.text;
1039
1529
  } else {
1040
- this.restartAjax = false;
1041
- this.ajaxLoading = true;
1042
- $.ajax(
1043
- $.extend({}, opts, {
1044
- url: opts.url,
1045
- dataType: 'json',
1046
- depData: remoteData,
1047
- data: opts.fullForm ?
1048
- $(elem).jProp('form').serializeArray() :
1049
- remoteData,
1050
- success: this.getResponse,
1051
- complete: this._complete
1052
- })
1053
- );
1054
- }
1055
- },
1056
- _complete: function(){
1057
- remoteValidate.ajaxLoading = false;
1058
- if(remoteValidate.restartAjax){
1059
- this.update(remoteValidate.restartAjax);
1060
- }
1061
- remoteValidate.restartAjax = false;
1062
- },
1063
- getResponse: function(data){
1064
- var old = webshims.refreshCustomValidityRules;
1065
- if(!data){
1066
- data = {message: '', valid: true};
1067
- } else if(typeof data == 'string'){
1068
- data = JSON.parse(data);
1530
+ data.box = $(elem)
1531
+ .wrap('<span class="placeholder-box placeholder-box-'+ (elem.nodeName || '').toLowerCase() +' placeholder-box-'+$.css(elem, 'float')+'" />')
1532
+ .parent()
1533
+ ;
1069
1534
  }
1070
-
1071
- remoteValidate.message = ('message' in data) ? data.message : !data.valid;
1072
- remoteValidate.lastMessage = remoteValidate.message;
1073
- remoteValidate.blockUpdate = true;
1074
- $(elem).triggerHandler('refreshvalidityui');
1075
- remoteValidate.message = 'async';
1076
- remoteValidate.blockUpdate = false;
1077
- },
1078
- getData: function(){
1079
- var data;
1080
- data = {};
1081
- data[$.prop(elem, 'name') || $.prop(elem, 'id')] = $(elem).val();
1082
- opts.depends.each(function(){
1083
- if($(this).is(':invalid')){
1084
- data = false;
1535
+ data.text
1536
+ .insertAfter(elem)
1537
+ .on('mousedown.placeholder', function(){
1538
+ changePlaceholderVisibility(this, false, false, data, 'focus');
1539
+ try {
1540
+ setTimeout(function(){
1541
+ elem.focus();
1542
+ }, 0);
1543
+ } catch(e){}
1085
1544
  return false;
1545
+ })
1546
+ ;
1547
+
1548
+
1549
+ $.each(['lineHeight', 'fontSize', 'fontFamily', 'fontWeight'], function(i, style){
1550
+ var prop = $.css(elem, style);
1551
+ if(data.text.css(style) != prop){
1552
+ data.text.css(style, prop);
1086
1553
  }
1087
- data[$.prop(this, 'name') || $.prop(this, 'id')] = $(this).val();
1088
1554
  });
1089
- return data;
1090
- },
1091
- getTempMessage: function(){
1092
- var message = 'async';
1093
- var remoteData, dataStr;
1094
- if(!data.remoteValidate.blockUpdate){
1095
- remoteData = this.getData();
1096
- if(!remoteData){
1097
- message = '';
1098
- } else {
1099
- try {
1100
- dataStr = JSON.stringify(remoteData);
1101
- } catch(er){}
1102
-
1103
- if(dataStr === this.lastString){
1104
- message = this.ajaxLoading ? 'async' : this.lastMessage;
1105
- } else {
1106
- this.lastString = dataStr;
1107
- this.lastMessage = 'async';
1108
- clearTimeout(data.remoteValidate.timer);
1109
- data.remoteValidate.timer = setTimeout(function(){
1110
- data.remoteValidate.update(remoteData);
1111
- }, 9);
1555
+ $.each(['Left', 'Top'], function(i, side){
1556
+ var size = (parseInt($.css(elem, 'padding'+ side), 10) || 0) + Math.max((parseInt($.css(elem, 'margin'+ side), 10) || 0), 0) + (parseInt($.css(elem, 'border'+ side +'Width'), 10) || 0);
1557
+ data.text.css('padding'+ side, size);
1558
+ });
1559
+
1560
+ $(elem)
1561
+ .onWSOff('updateshadowdom', function(){
1562
+ var height, width;
1563
+ if((width = elem.offsetWidth) || (height = elem.offsetHeight)){
1564
+ data.text
1565
+ .css({
1566
+ width: width,
1567
+ height: height
1568
+ })
1569
+ .css($(elem).position())
1570
+ ;
1112
1571
  }
1572
+ }, true)
1573
+ ;
1574
+
1575
+ } else {
1576
+ var reset = function(e){
1577
+ if($(elem).hasClass('placeholder-visible')){
1578
+ hidePlaceholder(elem, data, '');
1113
1579
 
1580
+ setTimeout(function(){
1581
+ if(!e || e.type != 'submit' || e.isDefaultPrevented()){
1582
+ changePlaceholderVisibility(elem, false, false, data );
1583
+ }
1584
+ }, 9);
1114
1585
  }
1115
- } else {
1116
- message = remoteValidate.message;
1586
+ };
1587
+
1588
+ $(elem).onWSOff('beforeunload', reset, false, window);
1589
+ data.box = $(elem);
1590
+ if(form){
1591
+ $(elem).onWSOff('submit', reset, false, form);
1117
1592
  }
1118
- return message;
1119
1593
  }
1120
- };
1121
- data.remoteValidate = remoteValidate;
1594
+
1595
+ return data;
1596
+ },
1597
+ update: function(elem, val){
1598
+ var type = ($.attr(elem, 'type') || $.prop(elem, 'type') || '').toLowerCase();
1599
+ if(!allowedPlaceholder[type] && !$.nodeName(elem, 'textarea')){
1600
+ webshims.warn('placeholder not allowed on input[type="'+type+'"], but it is a good fallback :-)');
1601
+ return;
1602
+ }
1603
+
1604
+
1605
+ var data = pHolder.create(elem);
1606
+ if(data.text){
1607
+ data.text.text(val);
1608
+ }
1609
+
1610
+ changePlaceholderVisibility(elem, false, val, data);
1611
+ }
1612
+ };
1613
+ })()
1614
+ ;
1615
+
1616
+ $.webshims.publicMethods = {
1617
+ pHolder: pHolder
1618
+ };
1619
+ polyfillElements.forEach(function(nodeName){
1620
+ var desc = webshims.defineNodeNameProperty(nodeName, 'placeholder', {
1621
+ attr: {
1622
+ set: function(val){
1623
+ var elem = this;
1624
+ if(bustedPlaceholder){
1625
+ webshims.data(elem, 'bustedPlaceholder', val);
1626
+ elem.placeholder = '';
1627
+ } else {
1628
+ webshims.contentAttr(elem, 'placeholder', val);
1629
+ }
1630
+ pHolder.update(elem, val);
1631
+ },
1632
+ get: function(){
1633
+ var placeholder;
1634
+ if(bustedPlaceholder){
1635
+ placeholder = webshims.data(this, 'bustedPlaceholder');
1636
+ }
1637
+ return placeholder || webshims.contentAttr(this, 'placeholder');
1638
+ }
1639
+ },
1640
+ reflect: true,
1641
+ initAttr: true
1642
+ });
1643
+ });
1644
+
1645
+
1646
+ polyfillElements.forEach(function(name){
1647
+ var placeholderValueDesc = {};
1648
+ var desc;
1649
+ ['attr', 'prop'].forEach(function(propType){
1650
+ placeholderValueDesc[propType] = {
1651
+ set: function(val){
1652
+ var elem = this;
1653
+ var placeholder;
1654
+ if(bustedPlaceholder){
1655
+ placeholder = webshims.data(elem, 'bustedPlaceholder');
1656
+ }
1657
+ if(!placeholder){
1658
+ placeholder = webshims.contentAttr(elem, 'placeholder');
1659
+ }
1660
+ $.removeData(elem, 'cachedValidity');
1661
+ var ret = desc[propType]._supset.call(elem, val);
1662
+ if(placeholder && 'value' in elem){
1663
+ changePlaceholderVisibility(elem, val, placeholder);
1664
+ }
1665
+ return ret;
1666
+ },
1667
+ get: function(){
1668
+ var elem = this;
1669
+ return $(elem).hasClass('placeholder-visible') ? '' : desc[propType]._supget.call(elem);
1670
+ }
1671
+ };
1672
+ });
1673
+ desc = webshims.defineNodeNameProperty(name, 'value', placeholderValueDesc);
1674
+ });
1675
+
1676
+ })();
1677
+
1678
+ (function(){
1679
+ var doc = document;
1680
+ if( 'value' in document.createElement('output') ){return;}
1681
+
1682
+ webshims.defineNodeNameProperty('output', 'value', {
1683
+ prop: {
1684
+ set: function(value){
1685
+ var setVal = $.data(this, 'outputShim');
1686
+ if(!setVal){
1687
+ setVal = outputCreate(this);
1688
+ }
1689
+ setVal(value);
1690
+ },
1691
+ get: function(){
1692
+ return webshims.contentAttr(this, 'value') || $(this).text() || '';
1693
+ }
1694
+ }
1695
+ });
1696
+
1697
+
1698
+ webshims.onNodeNamesPropertyModify('input', 'value', function(value, boolVal, type){
1699
+ if(type == 'removeAttr'){return;}
1700
+ var setVal = $.data(this, 'outputShim');
1701
+ if(setVal){
1702
+ setVal(value);
1122
1703
  }
1704
+ });
1705
+
1706
+ var outputCreate = function(elem){
1707
+ if(elem.getAttribute('aria-live')){return;}
1708
+ elem = $(elem);
1709
+ var value = (elem.text() || '').trim();
1710
+ var id = elem.prop('id');
1711
+ var htmlFor = elem.attr('for');
1712
+ var shim = $('<input class="output-shim" type="text" disabled name="'+ (elem.attr('name') || '')+'" value="'+value+'" style="display: none !important;" />').insertAfter(elem);
1713
+ var form = shim[0].form || doc;
1714
+ var setValue = function(val){
1715
+ shim[0].value = val;
1716
+ val = shim[0].value;
1717
+ elem.text(val);
1718
+ webshims.contentAttr(elem[0], 'value', val);
1719
+ };
1123
1720
 
1124
- return data.remoteValidate.getTempMessage();
1125
- }, 'remote error');
1126
- }
1127
- })();
1721
+ elem[0].defaultValue = value;
1722
+ webshims.contentAttr(elem[0], 'value', value);
1723
+
1724
+ elem.attr({'aria-live': 'polite'});
1725
+ if(id){
1726
+ shim.attr('id', id);
1727
+ elem.attr('aria-labelledby', elem.jProp('labels').map(function(){
1728
+ return webshims.getID(this);
1729
+ }).get().join(' '));
1730
+ }
1731
+ if(htmlFor){
1732
+ id = webshims.getID(elem);
1733
+ htmlFor.split(' ').forEach(function(control){
1734
+ control = document.getElementById(control);
1735
+ if(control){
1736
+ control.setAttribute('aria-controls', id);
1737
+ }
1738
+ });
1739
+ }
1740
+ elem.data('outputShim', setValue );
1741
+ shim.data('outputShim', setValue );
1742
+ return setValue;
1743
+ };
1744
+
1745
+ webshims.addReady(function(context, contextElem){
1746
+ $('output', context).add(contextElem.filter('output')).each(function(){
1747
+ outputCreate(this);
1748
+ });
1749
+ });
1750
+
1751
+ /*
1752
+ * Implements input event in all browsers
1753
+ */
1754
+ (function(){
1755
+ var noInputTriggerEvts = {updateInput: 1, input: 1},
1756
+ noInputTypes = {
1757
+ radio: 1,
1758
+ checkbox: 1,
1759
+ submit: 1,
1760
+ button: 1,
1761
+ image: 1,
1762
+ reset: 1,
1763
+ file: 1
1764
+
1765
+ //pro forma
1766
+ ,color: 1
1767
+ //,range: 1
1768
+ },
1769
+ observe = function(input){
1770
+ var timer,
1771
+ lastVal = input.prop('value'),
1772
+ trigger = function(e){
1773
+ //input === null
1774
+ if(!input){return;}
1775
+ var newVal = input.prop('value');
1776
+ if(newVal !== lastVal){
1777
+ lastVal = newVal;
1778
+ if(!e || !noInputTriggerEvts[e.type]){
1779
+ webshims.triggerInlineForm && webshims.triggerInlineForm(input[0], 'input');
1780
+ }
1781
+ }
1782
+ },
1783
+ extraTimer,
1784
+ extraTest = function(){
1785
+ clearTimeout(extraTimer);
1786
+ extraTimer = setTimeout(trigger, 9);
1787
+ },
1788
+ unbind = function(){
1789
+ input.unbind('focusout', unbind).unbind('keyup keypress keydown paste cut', extraTest).unbind('input change updateInput', trigger);
1790
+ clearInterval(timer);
1791
+ setTimeout(function(){
1792
+ trigger();
1793
+ input = null;
1794
+ }, 1);
1795
+
1796
+ }
1797
+ ;
1798
+
1799
+ clearInterval(timer);
1800
+ timer = setInterval(trigger, 200);
1801
+ extraTest();
1802
+ input.on({
1803
+ 'keyup keypress keydown paste cut': extraTest,
1804
+ focusout: unbind,
1805
+ 'input updateInput change': trigger
1806
+ });
1807
+ }
1808
+ ;
1809
+
1810
+ $(doc)
1811
+ .on('focusin', function(e){
1812
+ if( e.target && !e.target.readOnly && !e.target.disabled && (e.target.nodeName || '').toLowerCase() == 'input' && !noInputTypes[e.target.type] && !(webshims.data(e.target, 'implemented') || {}).inputwidgets){
1813
+ observe($(e.target));
1814
+ }
1815
+ })
1816
+ ;
1817
+ })();
1818
+ })();
1128
1819
 
1129
- });
1820
+
1821
+ });