fomantic-ui-sass 2.9.1 → 2.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/app/assets/fonts/semantic-ui/Lato-Bold.woff +0 -0
  4. data/app/assets/fonts/semantic-ui/Lato-Bold.woff2 +0 -0
  5. data/app/assets/fonts/semantic-ui/Lato-BoldItalic.woff +0 -0
  6. data/app/assets/fonts/semantic-ui/Lato-BoldItalic.woff2 +0 -0
  7. data/app/assets/fonts/semantic-ui/Lato-Italic.woff +0 -0
  8. data/app/assets/fonts/semantic-ui/Lato-Italic.woff2 +0 -0
  9. data/app/assets/fonts/semantic-ui/Lato-Regular.woff +0 -0
  10. data/app/assets/fonts/semantic-ui/Lato-Regular.woff2 +0 -0
  11. data/app/assets/fonts/semantic-ui/LatoLatin-Bold.woff +0 -0
  12. data/app/assets/fonts/semantic-ui/LatoLatin-Bold.woff2 +0 -0
  13. data/app/assets/fonts/semantic-ui/LatoLatin-BoldItalic.woff +0 -0
  14. data/app/assets/fonts/semantic-ui/LatoLatin-BoldItalic.woff2 +0 -0
  15. data/app/assets/fonts/semantic-ui/LatoLatin-Italic.woff +0 -0
  16. data/app/assets/fonts/semantic-ui/LatoLatin-Italic.woff2 +0 -0
  17. data/app/assets/fonts/semantic-ui/LatoLatin-Regular.woff +0 -0
  18. data/app/assets/fonts/semantic-ui/LatoLatin-Regular.woff2 +0 -0
  19. data/app/assets/javascripts/semantic-ui/accordion.js +4 -8
  20. data/app/assets/javascripts/semantic-ui/api.js +22 -15
  21. data/app/assets/javascripts/semantic-ui/calendar.js +1 -6
  22. data/app/assets/javascripts/semantic-ui/checkbox.js +4 -6
  23. data/app/assets/javascripts/semantic-ui/dimmer.js +3 -7
  24. data/app/assets/javascripts/semantic-ui/dropdown.js +58 -35
  25. data/app/assets/javascripts/semantic-ui/embed.js +2 -7
  26. data/app/assets/javascripts/semantic-ui/flyout.js +56 -86
  27. data/app/assets/javascripts/semantic-ui/form.js +216 -157
  28. data/app/assets/javascripts/semantic-ui/modal.js +58 -39
  29. data/app/assets/javascripts/semantic-ui/nag.js +17 -9
  30. data/app/assets/javascripts/semantic-ui/popup.js +46 -26
  31. data/app/assets/javascripts/semantic-ui/progress.js +3 -34
  32. data/app/assets/javascripts/semantic-ui/rating.js +1 -5
  33. data/app/assets/javascripts/semantic-ui/search.js +5 -8
  34. data/app/assets/javascripts/semantic-ui/shape.js +15 -41
  35. data/app/assets/javascripts/semantic-ui/sidebar.js +21 -64
  36. data/app/assets/javascripts/semantic-ui/site.js +1 -1
  37. data/app/assets/javascripts/semantic-ui/slider.js +130 -34
  38. data/app/assets/javascripts/semantic-ui/state.js +23 -20
  39. data/app/assets/javascripts/semantic-ui/sticky.js +17 -16
  40. data/app/assets/javascripts/semantic-ui/tab.js +18 -8
  41. data/app/assets/javascripts/semantic-ui/toast.js +19 -11
  42. data/app/assets/javascripts/semantic-ui/transition.js +11 -66
  43. data/app/assets/javascripts/semantic-ui/visibility.js +15 -6
  44. data/app/assets/stylesheets/semantic-ui/collections/_breadcrumb.scss +1 -1
  45. data/app/assets/stylesheets/semantic-ui/collections/_form.scss +118 -56
  46. data/app/assets/stylesheets/semantic-ui/collections/_grid.scss +113 -107
  47. data/app/assets/stylesheets/semantic-ui/collections/_menu.scss +39 -9
  48. data/app/assets/stylesheets/semantic-ui/collections/_message.scss +1 -1
  49. data/app/assets/stylesheets/semantic-ui/collections/_table.scss +66 -2
  50. data/app/assets/stylesheets/semantic-ui/elements/_button.scss +2 -2
  51. data/app/assets/stylesheets/semantic-ui/elements/_container.scss +62 -1
  52. data/app/assets/stylesheets/semantic-ui/elements/_divider.scss +1 -1
  53. data/app/assets/stylesheets/semantic-ui/elements/_emoji.scss +698 -250
  54. data/app/assets/stylesheets/semantic-ui/elements/_flag.scss +3 -2
  55. data/app/assets/stylesheets/semantic-ui/elements/_header.scss +1 -1
  56. data/app/assets/stylesheets/semantic-ui/elements/_icon.scss +62 -62
  57. data/app/assets/stylesheets/semantic-ui/elements/_image.scss +1 -1
  58. data/app/assets/stylesheets/semantic-ui/elements/_input.scss +61 -51
  59. data/app/assets/stylesheets/semantic-ui/elements/_label.scss +21 -2
  60. data/app/assets/stylesheets/semantic-ui/elements/_list.scss +13 -13
  61. data/app/assets/stylesheets/semantic-ui/elements/_loader.scss +282 -282
  62. data/app/assets/stylesheets/semantic-ui/elements/_placeholder.scss +1 -1
  63. data/app/assets/stylesheets/semantic-ui/elements/_rail.scss +1 -1
  64. data/app/assets/stylesheets/semantic-ui/elements/_reveal.scss +1 -1
  65. data/app/assets/stylesheets/semantic-ui/elements/_segment.scss +186 -37
  66. data/app/assets/stylesheets/semantic-ui/elements/_step.scss +4 -4
  67. data/app/assets/stylesheets/semantic-ui/elements/_text.scss +2 -2
  68. data/app/assets/stylesheets/semantic-ui/globals/_reset.scss +1 -1
  69. data/app/assets/stylesheets/semantic-ui/globals/_site.scss +1 -10
  70. data/app/assets/stylesheets/semantic-ui/modules/_accordion.scss +1 -1
  71. data/app/assets/stylesheets/semantic-ui/modules/_calendar.scss +145 -8
  72. data/app/assets/stylesheets/semantic-ui/modules/_checkbox.scss +89 -45
  73. data/app/assets/stylesheets/semantic-ui/modules/_dimmer.scss +3 -3
  74. data/app/assets/stylesheets/semantic-ui/modules/_dropdown.scss +126 -31
  75. data/app/assets/stylesheets/semantic-ui/modules/_embed.scss +2 -2
  76. data/app/assets/stylesheets/semantic-ui/modules/_flyout.scss +1 -1
  77. data/app/assets/stylesheets/semantic-ui/modules/_modal.scss +10 -3
  78. data/app/assets/stylesheets/semantic-ui/modules/_nag.scss +1 -1
  79. data/app/assets/stylesheets/semantic-ui/modules/_popup.scss +188 -42
  80. data/app/assets/stylesheets/semantic-ui/modules/_progress.scss +1 -1
  81. data/app/assets/stylesheets/semantic-ui/modules/_rating.scss +1 -1
  82. data/app/assets/stylesheets/semantic-ui/modules/_search.scss +26 -1
  83. data/app/assets/stylesheets/semantic-ui/modules/_shape.scss +1 -1
  84. data/app/assets/stylesheets/semantic-ui/modules/_sidebar.scss +1 -1
  85. data/app/assets/stylesheets/semantic-ui/modules/_slider.scss +9 -6
  86. data/app/assets/stylesheets/semantic-ui/modules/_sticky.scss +1 -1
  87. data/app/assets/stylesheets/semantic-ui/modules/_tab.scss +1 -1
  88. data/app/assets/stylesheets/semantic-ui/modules/_toast.scss +6 -1
  89. data/app/assets/stylesheets/semantic-ui/modules/_transition.scss +1 -1
  90. data/app/assets/stylesheets/semantic-ui/views/_ad.scss +1 -1
  91. data/app/assets/stylesheets/semantic-ui/views/_card.scss +1 -1
  92. data/app/assets/stylesheets/semantic-ui/views/_comment.scss +6 -1
  93. data/app/assets/stylesheets/semantic-ui/views/_feed.scss +486 -5
  94. data/app/assets/stylesheets/semantic-ui/views/_item.scss +7 -2
  95. data/app/assets/stylesheets/semantic-ui/views/_statistic.scss +1 -1
  96. data/lib/fomantic/ui/sass/version.rb +2 -2
  97. metadata +1 -1
@@ -22,7 +22,7 @@
22
22
  $.fn.form = function (parameters) {
23
23
  var
24
24
  $allModules = $(this),
25
- moduleSelector = $allModules.selector || '',
25
+ $window = $(window),
26
26
 
27
27
  time = Date.now(),
28
28
  performance = [],
@@ -61,6 +61,8 @@
61
61
  namespace,
62
62
  moduleNamespace,
63
63
  eventNamespace,
64
+ attachEventsSelector,
65
+ attachEventsAction,
64
66
 
65
67
  submitting = false,
66
68
  dirty = false,
@@ -75,6 +77,7 @@
75
77
  initialize: function () {
76
78
  // settings grabbed at run time
77
79
  module.get.settings();
80
+ $module.addClass(className.initial);
78
81
  if (methodInvoked) {
79
82
  if (instance === undefined) {
80
83
  module.instantiate();
@@ -128,10 +131,13 @@
128
131
  module.bindEvents();
129
132
  },
130
133
 
131
- submit: function () {
134
+ submit: function (event) {
132
135
  module.verbose('Submitting form', $module);
133
136
  submitting = true;
134
137
  $module.trigger('submit');
138
+ if (event) {
139
+ event.preventDefault();
140
+ }
135
141
  },
136
142
 
137
143
  attachEvents: function (selector, action) {
@@ -143,6 +149,9 @@
143
149
  module[action]();
144
150
  event.preventDefault();
145
151
  });
152
+
153
+ attachEventsSelector = selector;
154
+ attachEventsAction = action;
146
155
  },
147
156
 
148
157
  bindEvents: function () {
@@ -154,6 +163,7 @@
154
163
  .on('click' + eventNamespace, selector.reset, module.reset)
155
164
  .on('click' + eventNamespace, selector.clear, module.clear)
156
165
  ;
166
+ $field.on('invalid' + eventNamespace, module.event.field.invalid);
157
167
  if (settings.keyboardShortcuts) {
158
168
  $module.on('keydown' + eventNamespace, selector.field, module.event.field.keydown);
159
169
  }
@@ -168,10 +178,14 @@
168
178
 
169
179
  // Dirty events
170
180
  if (settings.preventLeaving) {
171
- $(window).on('beforeunload' + eventNamespace, module.event.beforeUnload);
181
+ $window.on('beforeunload' + eventNamespace, module.event.beforeUnload);
172
182
  }
173
183
 
174
- $field.on('change click keyup keydown blur', function (e) {
184
+ $field.on('change' + eventNamespace
185
+ + ' click' + eventNamespace
186
+ + ' keyup' + eventNamespace
187
+ + ' keydown' + eventNamespace
188
+ + ' blur' + eventNamespace, function (e) {
175
189
  module.determine.isDirty();
176
190
  });
177
191
 
@@ -182,6 +196,9 @@
182
196
  $module.on('clean' + eventNamespace, function (e) {
183
197
  settings.onClean.call();
184
198
  });
199
+ if (attachEventsSelector) {
200
+ module.attachEvents(attachEventsSelector, attachEventsAction);
201
+ }
185
202
  },
186
203
 
187
204
  clear: function () {
@@ -193,7 +210,7 @@
193
210
  $prompt = $fieldGroup.find(selector.prompt),
194
211
  $calendar = $field.closest(selector.uiCalendar),
195
212
  defaultValue = $field.data(metadata.defaultValue) || '',
196
- isCheckbox = $element.is(selector.uiCheckbox),
213
+ isCheckbox = $field.is(selector.checkbox),
197
214
  isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
198
215
  isCalendar = $calendar.length > 0 && module.can.useElement('calendar'),
199
216
  isErrored = $fieldGroup.hasClass(className.error)
@@ -227,9 +244,10 @@
227
244
  $calendar = $field.closest(selector.uiCalendar),
228
245
  $prompt = $fieldGroup.find(selector.prompt),
229
246
  defaultValue = $field.data(metadata.defaultValue),
230
- isCheckbox = $element.is(selector.uiCheckbox),
247
+ isCheckbox = $field.is(selector.checkbox),
231
248
  isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
232
249
  isCalendar = $calendar.length > 0 && module.can.useElement('calendar'),
250
+ isFile = $field.is(selector.file),
233
251
  isErrored = $fieldGroup.hasClass(className.error)
234
252
  ;
235
253
  if (defaultValue === undefined) {
@@ -244,13 +262,13 @@
244
262
  module.verbose('Resetting dropdown value', $element, defaultValue);
245
263
  $element.dropdown('restore defaults', true);
246
264
  } else if (isCheckbox) {
247
- module.verbose('Resetting checkbox value', $element, defaultValue);
265
+ module.verbose('Resetting checkbox value', $field, defaultValue);
248
266
  $field.prop('checked', defaultValue);
249
267
  } else if (isCalendar) {
250
268
  $calendar.calendar('set date', defaultValue);
251
269
  } else {
252
270
  module.verbose('Resetting field value', $field, defaultValue);
253
- $field.val(defaultValue);
271
+ $field.val(isFile ? '' : defaultValue);
254
272
  }
255
273
  });
256
274
  module.remove.states();
@@ -261,8 +279,12 @@
261
279
  var
262
280
  allValid = true
263
281
  ;
264
- $.each(validation, function (fieldName, field) {
265
- if (!module.validate.field(field, fieldName, true)) {
282
+ $field.each(function (index, el) {
283
+ var $el = $(el),
284
+ validation = module.get.validation($el) || {},
285
+ identifier = module.get.identifier(validation, $el)
286
+ ;
287
+ if (!module.validate.field(validation, identifier, true)) {
266
288
  allValid = false;
267
289
  }
268
290
  });
@@ -386,6 +408,13 @@
386
408
  $module.off(eventNamespace);
387
409
  $field.off(eventNamespace);
388
410
  $submit.off(eventNamespace);
411
+ if (settings.preventLeaving) {
412
+ $window.off(eventNamespace);
413
+ }
414
+ if (attachEventsSelector) {
415
+ $(attachEventsSelector).off(eventNamespace);
416
+ attachEventsSelector = undefined;
417
+ }
389
418
  },
390
419
 
391
420
  event: {
@@ -411,9 +440,8 @@
411
440
  if (!event.ctrlKey && key === keyCode.enter && isInput && !isInDropdown && !isCheckbox) {
412
441
  if (!keyHeldDown) {
413
442
  $field.one('keyup' + eventNamespace, module.event.field.keyup);
414
- module.submit();
443
+ module.submit(event);
415
444
  module.debug('Enter pressed on input submitting form');
416
- event.preventDefault();
417
445
  }
418
446
  keyHeldDown = true;
419
447
  }
@@ -421,15 +449,18 @@
421
449
  keyup: function () {
422
450
  keyHeldDown = false;
423
451
  },
452
+ invalid: function (event) {
453
+ event.preventDefault();
454
+ },
424
455
  blur: function (event) {
425
456
  var
426
457
  $field = $(this),
427
- $fieldGroup = $field.closest($group),
428
- validationRules = module.get.validation($field)
458
+ validationRules = module.get.validation($field) || {},
459
+ identifier = module.get.identifier(validationRules, $field)
429
460
  ;
430
- if (validationRules && (settings.on === 'blur' || ($fieldGroup.hasClass(className.error) && settings.revalidate))) {
461
+ if (settings.on === 'blur' || (!$module.hasClass(className.initial) && settings.revalidate)) {
431
462
  module.debug('Revalidating field', $field, validationRules);
432
- module.validate.field(validationRules);
463
+ module.validate.field(validationRules, identifier);
433
464
  if (!settings.inline) {
434
465
  module.validate.form(false, true);
435
466
  }
@@ -438,14 +469,14 @@
438
469
  change: function (event) {
439
470
  var
440
471
  $field = $(this),
441
- $fieldGroup = $field.closest($group),
442
- validationRules = module.get.validation($field)
472
+ validationRules = module.get.validation($field) || {},
473
+ identifier = module.get.identifier(validationRules, $field)
443
474
  ;
444
- if (validationRules && (settings.on === 'change' || ($fieldGroup.hasClass(className.error) && settings.revalidate))) {
475
+ if (settings.on === 'change' || (!$module.hasClass(className.initial) && settings.revalidate)) {
445
476
  clearTimeout(module.timer);
446
477
  module.timer = setTimeout(function () {
447
478
  module.debug('Revalidating field', $field, validationRules);
448
- module.validate.field(validationRules);
479
+ module.validate.field(validationRules, identifier);
449
480
  if (!settings.inline) {
450
481
  module.validate.form(false, true);
451
482
  }
@@ -487,18 +518,7 @@
487
518
  return rule.type;
488
519
  },
489
520
  changeEvent: function (type, $input) {
490
- if (type === 'checkbox' || type === 'radio' || type === 'hidden' || $input.is('select')) {
491
- return 'change';
492
- }
493
-
494
- return module.get.inputEvent();
495
- },
496
- inputEvent: function () {
497
- return document.createElement('input').oninput !== undefined
498
- ? 'input'
499
- : (document.createElement('input').onpropertychange !== undefined
500
- ? 'propertychange'
501
- : 'keyup');
521
+ return ['file', 'checkbox', 'radio', 'hidden'].indexOf(type) >= 0 || $input.is('select') ? 'change' : 'input';
502
522
  },
503
523
  fieldsFromShorthand: function (fields) {
504
524
  var
@@ -522,6 +542,9 @@
522
542
 
523
543
  return fullFields;
524
544
  },
545
+ identifier: function (validation, $el) {
546
+ return validation.identifier || $el.attr('id') || $el.attr('name') || $el.data(metadata.validate);
547
+ },
525
548
  prompt: function (rule, field) {
526
549
  var
527
550
  ruleName = module.get.ruleName(rule),
@@ -533,14 +556,12 @@
533
556
  : rule.prompt || settings.prompt[ruleName] || settings.text.unspecifiedRule,
534
557
  requiresValue = prompt.search('{value}') !== -1,
535
558
  requiresName = prompt.search('{name}') !== -1,
536
- $label,
537
- name,
538
559
  parts,
539
560
  suffixPrompt
540
561
  ;
541
- if (ancillary && ['integer', 'decimal', 'number'].indexOf(ruleName) >= 0 && ancillary.indexOf('..') >= 0) {
562
+ if (ancillary && ['integer', 'decimal', 'number', 'size'].indexOf(ruleName) >= 0 && ancillary.indexOf('..') >= 0) {
542
563
  parts = ancillary.split('..', 2);
543
- if (!rule.prompt) {
564
+ if (!rule.prompt && ruleName !== 'size') {
544
565
  suffixPrompt = parts[0] === ''
545
566
  ? settings.prompt.maxValue.replace(/{ruleValue}/g, '{max}')
546
567
  : (parts[1] === ''
@@ -551,15 +572,14 @@
551
572
  prompt = prompt.replace(/{min}/g, parts[0]);
552
573
  prompt = prompt.replace(/{max}/g, parts[1]);
553
574
  }
575
+ if (ancillary && ['match', 'different'].indexOf(ruleName) >= 0) {
576
+ prompt = prompt.replace(/{ruleValue}/g, module.get.fieldLabel(ancillary, true));
577
+ }
554
578
  if (requiresValue) {
555
579
  prompt = prompt.replace(/{value}/g, $field.val());
556
580
  }
557
581
  if (requiresName) {
558
- $label = $field.closest(selector.group).find('label').eq(0);
559
- name = $label.length === 1
560
- ? $label.text()
561
- : $field.prop('placeholder') || settings.text.unspecifiedField;
562
- prompt = prompt.replace(/{name}/g, name);
582
+ prompt = prompt.replace(/{name}/g, module.get.fieldLabel($field));
563
583
  }
564
584
  prompt = prompt.replace(/{identifier}/g, field.identifier);
565
585
  prompt = prompt.replace(/{ruleValue}/g, ancillary);
@@ -599,7 +619,7 @@
599
619
  // refresh selector cache
600
620
  (instance || module).refresh();
601
621
  },
602
- field: function (identifier) {
622
+ field: function (identifier, strict) {
603
623
  module.verbose('Finding field with identifier', identifier);
604
624
  identifier = module.escape.string(identifier);
605
625
  var t;
@@ -621,18 +641,29 @@
621
641
  }
622
642
  module.error(error.noField.replace('{identifier}', identifier));
623
643
 
624
- return $('<input/>');
644
+ return strict ? $() : $('<input/>');
625
645
  },
626
- fields: function (fields) {
646
+ fields: function (fields, strict) {
627
647
  var
628
648
  $fields = $()
629
649
  ;
630
650
  $.each(fields, function (index, name) {
631
- $fields = $fields.add(module.get.field(name));
651
+ $fields = $fields.add(module.get.field(name, strict));
632
652
  });
633
653
 
634
654
  return $fields;
635
655
  },
656
+ fieldLabel: function (identifier, useIdAsFallback) {
657
+ var $field = typeof identifier === 'string'
658
+ ? module.get.field(identifier)
659
+ : identifier,
660
+ $label = $field.closest(selector.group).find('label:not(:empty)').eq(0)
661
+ ;
662
+
663
+ return $label.length === 1
664
+ ? $label.text()
665
+ : $field.prop('placeholder') || (useIdAsFallback ? identifier : settings.text.unspecifiedField);
666
+ },
636
667
  validation: function ($field) {
637
668
  var
638
669
  fieldValidation,
@@ -655,20 +686,22 @@
655
686
 
656
687
  return fieldValidation || false;
657
688
  },
658
- value: function (field) {
689
+ value: function (field, strict) {
659
690
  var
660
691
  fields = [],
661
- results
692
+ results,
693
+ resultKeys
662
694
  ;
663
695
  fields.push(field);
664
- results = module.get.values.call(element, fields);
696
+ results = module.get.values.call(element, fields, strict);
697
+ resultKeys = Object.keys(results);
665
698
 
666
- return results[field];
699
+ return resultKeys.length > 0 ? results[resultKeys[0]] : undefined;
667
700
  },
668
- values: function (fields) {
701
+ values: function (fields, strict) {
669
702
  var
670
- $fields = Array.isArray(fields)
671
- ? module.get.fields(fields)
703
+ $fields = Array.isArray(fields) && fields.length > 0
704
+ ? module.get.fields(fields, strict)
672
705
  : $field,
673
706
  values = {}
674
707
  ;
@@ -786,16 +819,8 @@
786
819
 
787
820
  field: function (identifier) {
788
821
  module.verbose('Checking for existence of a field with identifier', identifier);
789
- identifier = module.escape.string(identifier);
790
- if (typeof identifier !== 'string') {
791
- module.error(error.identifier, identifier);
792
- }
793
822
 
794
- return (
795
- $field.filter('#' + identifier).length > 0
796
- || $field.filter('[name="' + identifier + '"]').length > 0
797
- || $field.filter('[data-' + metadata.validate + '="' + identifier + '"]').length > 0
798
- );
823
+ return module.get.field(identifier, true).length > 0;
799
824
  },
800
825
 
801
826
  },
@@ -819,6 +844,22 @@
819
844
  },
820
845
  },
821
846
 
847
+ checkErrors: function (errors, internal) {
848
+ if (!errors || errors.length === 0) {
849
+ if (!internal) {
850
+ module.error(settings.error.noErrorMessage);
851
+ }
852
+
853
+ return false;
854
+ }
855
+ if (!internal) {
856
+ errors = typeof errors === 'string'
857
+ ? [errors]
858
+ : errors;
859
+ }
860
+
861
+ return errors;
862
+ },
822
863
  add: {
823
864
  // alias
824
865
  rule: function (name, rules) {
@@ -862,15 +903,17 @@
862
903
  module.refreshEvents();
863
904
  },
864
905
  prompt: function (identifier, errors, internal) {
906
+ errors = module.checkErrors(errors);
907
+ if (errors === false) {
908
+ return;
909
+ }
865
910
  var
866
911
  $field = module.get.field(identifier),
867
912
  $fieldGroup = $field.closest($group),
868
913
  $prompt = $fieldGroup.children(selector.prompt),
869
- promptExists = $prompt.length > 0
914
+ promptExists = $prompt.length > 0,
915
+ canTransition = settings.transition && module.can.useElement('transition')
870
916
  ;
871
- errors = typeof errors === 'string'
872
- ? [errors]
873
- : errors;
874
917
  module.verbose('Adding field error state', identifier);
875
918
  if (!internal) {
876
919
  $fieldGroup
@@ -878,8 +921,22 @@
878
921
  ;
879
922
  }
880
923
  if (settings.inline) {
924
+ if (promptExists) {
925
+ if (canTransition) {
926
+ if ($prompt.transition('is animating')) {
927
+ $prompt.transition('stop all');
928
+ }
929
+ } else if ($prompt.is(':animated')) {
930
+ $prompt.stop(true, true);
931
+ }
932
+ $prompt = $fieldGroup.children(selector.prompt);
933
+ promptExists = $prompt.length > 0;
934
+ }
881
935
  if (!promptExists) {
882
936
  $prompt = $('<div/>').addClass(className.label);
937
+ if (!canTransition) {
938
+ $prompt.css('display', 'none');
939
+ }
883
940
  $prompt
884
941
  .appendTo($fieldGroup)
885
942
  ;
@@ -888,7 +945,7 @@
888
945
  .html(settings.templates.prompt(errors))
889
946
  ;
890
947
  if (!promptExists) {
891
- if (settings.transition && module.can.useElement('transition') && $module.transition('is supported')) {
948
+ if (canTransition) {
892
949
  module.verbose('Displaying error with css transition', settings.transition);
893
950
  $prompt.transition(settings.transition + ' in', settings.duration);
894
951
  } else {
@@ -897,17 +954,46 @@
897
954
  .fadeIn(settings.duration)
898
955
  ;
899
956
  }
900
- } else {
901
- module.verbose('Inline errors are disabled, no inline error added', identifier);
902
957
  }
958
+ } else {
959
+ module.verbose('Inline errors are disabled, no inline error added', identifier);
903
960
  }
904
961
  },
905
962
  errors: function (errors) {
963
+ errors = module.checkErrors(errors);
964
+ if (errors === false) {
965
+ return;
966
+ }
906
967
  module.debug('Adding form error messages', errors);
907
968
  module.set.error();
908
- $message
909
- .html(settings.templates.error(errors))
969
+ var customErrors = [],
970
+ tempErrors
910
971
  ;
972
+ if ($.isPlainObject(errors)) {
973
+ $.each(Object.keys(errors), function (i, id) {
974
+ if (module.checkErrors(errors[id], true) !== false) {
975
+ if (settings.inline) {
976
+ module.add.prompt(id, errors[id]);
977
+ } else {
978
+ tempErrors = module.checkErrors(errors[id]);
979
+ if (tempErrors !== false) {
980
+ $.each(tempErrors, function (index, tempError) {
981
+ customErrors.push(settings.prompt.addErrors
982
+ .replace(/{name}/g, module.get.fieldLabel(id))
983
+ .replace(/{error}/g, tempError));
984
+ });
985
+ }
986
+ }
987
+ }
988
+ });
989
+ } else {
990
+ customErrors = errors;
991
+ }
992
+ if (customErrors.length > 0) {
993
+ $message
994
+ .html(settings.templates.error(customErrors))
995
+ ;
996
+ }
911
997
  },
912
998
  },
913
999
 
@@ -917,7 +1003,7 @@
917
1003
  $message.empty();
918
1004
  },
919
1005
  states: function () {
920
- $module.removeClass(className.error).removeClass(className.success);
1006
+ $module.removeClass(className.error).removeClass(className.success).addClass(className.initial);
921
1007
  if (!settings.inline) {
922
1008
  module.remove.errors();
923
1009
  }
@@ -984,7 +1070,7 @@
984
1070
  ;
985
1071
  if (settings.inline && $prompt.is(':visible')) {
986
1072
  module.verbose('Removing prompt for field', identifier);
987
- if (settings.transition && module.can.useElement('transition') && $module.transition('is supported')) {
1073
+ if (settings.transition && module.can.useElement('transition')) {
988
1074
  $prompt.transition(settings.transition + ' out', settings.duration, function () {
989
1075
  $prompt.remove();
990
1076
  });
@@ -1012,15 +1098,19 @@
1012
1098
  $el = $(el),
1013
1099
  $parent = $el.parent(),
1014
1100
  isCheckbox = $el.filter(selector.checkbox).length > 0,
1015
- isDropdown = $parent.is(selector.uiDropdown) && module.can.useElement('dropdown'),
1016
- $calendar = $el.closest(selector.uiCalendar),
1017
- isCalendar = $calendar.length > 0 && module.can.useElement('calendar'),
1101
+ isDropdown = ($parent.is(selector.uiDropdown) || $el.is(selector.uiDropdown)) && module.can.useElement('dropdown'),
1102
+ $calendar = $el.closest(selector.uiCalendar),
1103
+ isCalendar = $calendar.length > 0 && module.can.useElement('calendar'),
1018
1104
  value = isCheckbox
1019
1105
  ? $el.is(':checked')
1020
1106
  : $el.val()
1021
1107
  ;
1022
1108
  if (isDropdown) {
1023
- $parent.dropdown('save defaults');
1109
+ if ($parent.is(selector.uiDropdown)) {
1110
+ $parent.dropdown('save defaults');
1111
+ } else {
1112
+ $el.dropdown('save defaults');
1113
+ }
1024
1114
  } else if (isCalendar) {
1025
1115
  $calendar.calendar('refresh');
1026
1116
  }
@@ -1051,6 +1141,7 @@
1051
1141
  $field = module.get.field(key),
1052
1142
  $element = $field.parent(),
1053
1143
  $calendar = $field.closest(selector.uiCalendar),
1144
+ isFile = $field.is(selector.file),
1054
1145
  isMultiple = Array.isArray(value),
1055
1146
  isCheckbox = $element.is(selector.uiCheckbox) && module.can.useElement('checkbox'),
1056
1147
  isDropdown = $element.is(selector.uiDropdown) && module.can.useElement('dropdown'),
@@ -1093,7 +1184,7 @@
1093
1184
  $calendar.calendar('set date', value);
1094
1185
  } else {
1095
1186
  module.verbose('Setting field value', value, $field);
1096
- $field.val(value);
1187
+ $field.val(isFile ? '' : value);
1097
1188
  }
1098
1189
  }
1099
1190
  });
@@ -1149,7 +1240,7 @@
1149
1240
  return rule.type === 'empty';
1150
1241
  }) !== 0
1151
1242
  : false,
1152
- identifier = validation.identifier || $el.attr('id') || $el.attr('name') || $el.data(metadata.validate)
1243
+ identifier = module.get.identifier(validation, $el)
1153
1244
  ;
1154
1245
  if (isRequired && !isDisabled && !hasEmptyRule && identifier !== undefined) {
1155
1246
  if (isCheckbox) {
@@ -1181,7 +1272,7 @@
1181
1272
  if (keyHeldDown) {
1182
1273
  return false;
1183
1274
  }
1184
-
1275
+ $module.removeClass(className.initial);
1185
1276
  // reset errors
1186
1277
  formErrors = [];
1187
1278
  if (module.determine.isValid()) {
@@ -1253,13 +1344,25 @@
1253
1344
  ? module.get.field(field.depends)
1254
1345
  : false,
1255
1346
  fieldValid = true,
1256
- fieldErrors = []
1347
+ fieldErrors = [],
1348
+ isDisabled = $field.filter(':not(:disabled)').length === 0,
1349
+ validationMessage = $field[0].validationMessage,
1350
+ errorLimit
1257
1351
  ;
1258
1352
  if (!field.identifier) {
1259
1353
  module.debug('Using field name as identifier', identifier);
1260
1354
  field.identifier = identifier;
1261
1355
  }
1262
- var isDisabled = $field.filter(':not(:disabled)').length === 0;
1356
+ if (validationMessage) {
1357
+ module.debug('Field is natively invalid', identifier);
1358
+ fieldErrors.push(validationMessage);
1359
+ fieldValid = false;
1360
+ if (showErrors) {
1361
+ $field.closest($group).addClass(className.error);
1362
+ }
1363
+ } else if (showErrors) {
1364
+ $field.closest($group).removeClass(className.error);
1365
+ }
1263
1366
  if (isDisabled) {
1264
1367
  module.debug('Field is disabled. Skipping', identifier);
1265
1368
  } else if (field.optional && module.is.blank($field)) {
@@ -1267,11 +1370,9 @@
1267
1370
  } else if (field.depends && module.is.empty($dependsField)) {
1268
1371
  module.debug('Field depends on another value that is not present or empty. Skipping', $dependsField);
1269
1372
  } else if (field.rules !== undefined) {
1270
- if (showErrors) {
1271
- $field.closest($group).removeClass(className.error);
1272
- }
1373
+ errorLimit = field.errorLimit || settings.errorLimit;
1273
1374
  $.each(field.rules, function (index, rule) {
1274
- if (module.has.field(identifier)) {
1375
+ if (module.has.field(identifier) && (!errorLimit || fieldErrors.length < errorLimit)) {
1275
1376
  var invalidFields = module.validate.rule(field, rule, true) || [];
1276
1377
  if (invalidFields.length > 0) {
1277
1378
  module.debug('Field is invalid', identifier, rule.type);
@@ -1286,7 +1387,7 @@
1286
1387
  }
1287
1388
  if (fieldValid) {
1288
1389
  if (showErrors) {
1289
- module.remove.prompt(identifier, fieldErrors);
1390
+ module.remove.prompt(identifier);
1290
1391
  settings.onValid.call($field);
1291
1392
  }
1292
1393
  } else {
@@ -1320,7 +1421,7 @@
1320
1421
  ? String(value + '').trim()
1321
1422
  : String(value + ''));
1322
1423
 
1323
- return ruleFunction.call(field, value, ancillary, $module);
1424
+ return ruleFunction.call(field, value, ancillary, module);
1324
1425
  }
1325
1426
  ;
1326
1427
  if (!isFunction(ruleFunction)) {
@@ -1408,7 +1509,7 @@
1408
1509
  });
1409
1510
  }
1410
1511
  clearTimeout(module.performance.timer);
1411
- module.performance.timer = setTimeout(module.performance.display, 500);
1512
+ module.performance.timer = setTimeout(function () { module.performance.display(); }, 500);
1412
1513
  },
1413
1514
  display: function () {
1414
1515
  var
@@ -1421,9 +1522,6 @@
1421
1522
  totalTime += data['Execution Time'];
1422
1523
  });
1423
1524
  title += ' ' + totalTime + 'ms';
1424
- if (moduleSelector) {
1425
- title += ' \'' + moduleSelector + '\'';
1426
- }
1427
1525
  if ($allModules.length > 1) {
1428
1526
  title += ' (' + $allModules.length + ')';
1429
1527
  }
@@ -1526,6 +1624,7 @@
1526
1624
  preventLeaving: false,
1527
1625
  errorFocus: true,
1528
1626
  dateHandling: 'date', // 'date', 'input', 'formatter'
1627
+ errorLimit: 0,
1529
1628
 
1530
1629
  onValid: function () {},
1531
1630
  onInvalid: function () {},
@@ -1579,27 +1678,30 @@
1579
1678
  isExactly: '{name} must be exactly "{ruleValue}"',
1580
1679
  not: '{name} cannot be set to "{ruleValue}"',
1581
1680
  notExactly: '{name} cannot be set to exactly "{ruleValue}"',
1582
- contain: '{name} must contain "{ruleValue}"',
1583
- containExactly: '{name} must contain exactly "{ruleValue}"',
1584
- doesntContain: '{name} cannot contain "{ruleValue}"',
1681
+ contains: '{name} must contain "{ruleValue}"',
1682
+ containsExactly: '{name} must contain exactly "{ruleValue}"',
1683
+ doesntContain: '{name} cannot contain "{ruleValue}"',
1585
1684
  doesntContainExactly: '{name} cannot contain exactly "{ruleValue}"',
1586
1685
  minLength: '{name} must be at least {ruleValue} characters',
1587
1686
  exactLength: '{name} must be exactly {ruleValue} characters',
1588
1687
  maxLength: '{name} cannot be longer than {ruleValue} characters',
1688
+ size: '{name} must have a length between {min} and {max} characters',
1589
1689
  match: '{name} must match {ruleValue} field',
1590
1690
  different: '{name} must have a different value than {ruleValue} field',
1591
1691
  creditCard: '{name} must be a valid credit card number',
1592
1692
  minCount: '{name} must have at least {ruleValue} choices',
1593
1693
  exactCount: '{name} must have exactly {ruleValue} choices',
1594
1694
  maxCount: '{name} must have {ruleValue} or less choices',
1695
+ addErrors: '{name}: {error}',
1595
1696
  },
1596
1697
 
1597
1698
  selector: {
1598
1699
  checkbox: 'input[type="checkbox"], input[type="radio"]',
1599
1700
  clear: '.clear',
1600
- field: 'input:not(.search):not([type="file"]):not([type="reset"]):not([type="button"]):not([type="submit"]), textarea, select',
1701
+ field: 'input:not(.search):not([type="reset"]):not([type="button"]):not([type="submit"]), textarea, select',
1702
+ file: 'input[type="file"]',
1601
1703
  group: '.field',
1602
- input: 'input:not([type="file"])',
1704
+ input: 'input',
1603
1705
  message: '.error.message',
1604
1706
  prompt: '.prompt.label',
1605
1707
  radio: 'input[type="radio"]',
@@ -1611,6 +1713,7 @@
1611
1713
  },
1612
1714
 
1613
1715
  className: {
1716
+ initial: 'initial',
1614
1717
  error: 'error',
1615
1718
  label: 'ui basic red pointing prompt label',
1616
1719
  pressed: 'down',
@@ -1620,11 +1723,11 @@
1620
1723
  },
1621
1724
 
1622
1725
  error: {
1623
- identifier: 'You must specify a string identifier for each field',
1624
1726
  method: 'The method you called is not defined.',
1625
1727
  noRule: 'There is no rule matching the one you specified',
1626
1728
  noField: 'Field identifier {identifier} not found',
1627
1729
  noElement: 'This module requires ui {element}',
1730
+ noErrorMessage: 'No error message provided',
1628
1731
  },
1629
1732
 
1630
1733
  templates: {
@@ -1746,7 +1849,7 @@
1746
1849
  integer: function (value, range) {
1747
1850
  return $.fn.form.settings.rules.range(value, range, 'integer');
1748
1851
  },
1749
- range: function (value, range, regExp) {
1852
+ range: function (value, range, regExp, testLength) {
1750
1853
  if (typeof regExp === 'string') {
1751
1854
  regExp = $.fn.form.settings.regExp[regExp];
1752
1855
  }
@@ -1775,6 +1878,9 @@
1775
1878
  max = parts[1] - 0;
1776
1879
  }
1777
1880
  }
1881
+ if (testLength) {
1882
+ value = value.length;
1883
+ }
1778
1884
 
1779
1885
  return (
1780
1886
  regExp.test(value)
@@ -1860,51 +1966,27 @@
1860
1966
  },
1861
1967
 
1862
1968
  // is at least string length
1863
- minLength: function (value, requiredLength) {
1864
- return value !== undefined
1865
- ? value.length >= requiredLength
1866
- : false;
1969
+ minLength: function (value, minLength) {
1970
+ return $.fn.form.settings.rules.range(value, minLength + '..', 'integer', true);
1867
1971
  },
1868
1972
 
1869
1973
  // is exactly length
1870
1974
  exactLength: function (value, requiredLength) {
1871
- return value !== undefined
1872
- ? value.length === Number(requiredLength)
1873
- : false;
1975
+ return $.fn.form.settings.rules.range(value, requiredLength + '..' + requiredLength, 'integer', true);
1874
1976
  },
1875
1977
 
1876
1978
  // is less than length
1877
1979
  maxLength: function (value, maxLength) {
1878
- return value !== undefined
1879
- ? value.length <= maxLength
1880
- : false;
1980
+ return $.fn.form.settings.rules.range(value, '..' + maxLength, 'integer', true);
1981
+ },
1982
+
1983
+ size: function (value, range) {
1984
+ return $.fn.form.settings.rules.range(value, range, 'integer', true);
1881
1985
  },
1882
1986
 
1883
1987
  // matches another field
1884
- match: function (value, identifier, $module) {
1885
- var
1886
- matchingValue,
1887
- matchingElement
1888
- ;
1889
- matchingElement = $module.find('[data-validate="' + identifier + '"]');
1890
- if (matchingElement.length > 0) {
1891
- matchingValue = matchingElement.val();
1892
- } else {
1893
- matchingElement = $module.find('#' + identifier);
1894
- if (matchingElement.length > 0) {
1895
- matchingValue = matchingElement.val();
1896
- } else {
1897
- matchingElement = $module.find('[name="' + identifier + '"]');
1898
- if (matchingElement.length > 0) {
1899
- matchingValue = matchingElement.val();
1900
- } else {
1901
- matchingElement = $module.find('[name="' + identifier + '[]"]');
1902
- if (matchingElement.length > 0) {
1903
- matchingValue = matchingElement;
1904
- }
1905
- }
1906
- }
1907
- }
1988
+ match: function (value, identifier, module) {
1989
+ var matchingValue = module.get.value(identifier, true);
1908
1990
 
1909
1991
  return matchingValue !== undefined
1910
1992
  ? value.toString() === matchingValue.toString()
@@ -1912,31 +1994,8 @@
1912
1994
  },
1913
1995
 
1914
1996
  // different than another field
1915
- different: function (value, identifier, $module) {
1916
- // use either id or name of field
1917
- var
1918
- matchingValue,
1919
- matchingElement
1920
- ;
1921
- matchingElement = $module.find('[data-validate="' + identifier + '"]');
1922
- if (matchingElement.length > 0) {
1923
- matchingValue = matchingElement.val();
1924
- } else {
1925
- matchingElement = $module.find('#' + identifier);
1926
- if (matchingElement.length > 0) {
1927
- matchingValue = matchingElement.val();
1928
- } else {
1929
- matchingElement = $module.find('[name="' + identifier + '"]');
1930
- if (matchingElement.length > 0) {
1931
- matchingValue = matchingElement.val();
1932
- } else {
1933
- matchingElement = $module.find('[name="' + identifier + '[]"]');
1934
- if (matchingElement.length > 0) {
1935
- matchingValue = matchingElement;
1936
- }
1937
- }
1938
- }
1939
- }
1997
+ different: function (value, identifier, module) {
1998
+ var matchingValue = module.get.value(identifier, true);
1940
1999
 
1941
2000
  return matchingValue !== undefined
1942
2001
  ? value.toString() !== matchingValue.toString()