webshims-rails 1.11.1 → 1.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ });