@pageboard/html 0.14.19 → 0.14.21

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 (110) hide show
  1. package/elements/accordion.js +1 -1
  2. package/elements/fieldsets.js +1 -1
  3. package/elements/form.js +2 -2
  4. package/elements/grid.js +1 -1
  5. package/elements/image.js +1 -1
  6. package/elements/input-file.js +2 -2
  7. package/elements/input-property.js +12 -13
  8. package/elements/inputs.js +5 -5
  9. package/elements/layout.js +1 -1
  10. package/elements/link.js +2 -2
  11. package/elements/menu.js +2 -2
  12. package/elements/navigation.js +1 -1
  13. package/elements/page.js +1 -1
  14. package/elements/paragraph.js +2 -2
  15. package/elements/query-tags.js +1 -1
  16. package/elements/tab.js +1 -1
  17. package/elements/table.js +1 -1
  18. package/elements/template.js +1 -1
  19. package/package.json +3 -8
  20. package/ui/card.css +3 -3
  21. package/ui/components/accordion.css +241 -0
  22. package/ui/components/accordion.js +613 -0
  23. package/ui/components/ad.css +275 -0
  24. package/ui/components/api.js +1167 -0
  25. package/ui/components/breadcrumb.css +122 -0
  26. package/ui/components/button.css +3525 -0
  27. package/ui/components/card.css +939 -0
  28. package/ui/components/checkbox.css +604 -0
  29. package/ui/components/checkbox.js +831 -0
  30. package/ui/components/colorize.js +274 -0
  31. package/ui/components/comment.css +268 -0
  32. package/ui/components/container.css +149 -0
  33. package/ui/components/dimmer.css +224 -0
  34. package/ui/components/dimmer.js +733 -0
  35. package/ui/components/divider.css +253 -0
  36. package/ui/components/dropdown.css +1448 -0
  37. package/ui/components/dropdown.js +3955 -0
  38. package/ui/components/embed.css +160 -0
  39. package/ui/components/embed.js +706 -0
  40. package/ui/components/feed.css +281 -0
  41. package/ui/components/flag.css +1035 -0
  42. package/ui/components/form.css +1011 -0
  43. package/ui/components/form.js +1706 -0
  44. package/ui/components/grid.css +1941 -0
  45. package/ui/components/header.css +719 -0
  46. package/ui/components/icon.css +4777 -0
  47. package/ui/components/image.css +310 -0
  48. package/ui/components/input.css +469 -0
  49. package/ui/components/item.css +464 -0
  50. package/ui/components/label.css +1281 -0
  51. package/ui/components/list.css +943 -0
  52. package/ui/components/loader.css +339 -0
  53. package/ui/components/menu.css +1940 -0
  54. package/ui/components/message.css +468 -0
  55. package/ui/components/modal.css +617 -0
  56. package/ui/components/modal.js +1034 -0
  57. package/ui/components/nag.css +145 -0
  58. package/ui/components/nag.js +507 -0
  59. package/ui/components/placeholder.css +229 -0
  60. package/ui/components/popup.css +640 -0
  61. package/ui/components/popup.js +1532 -0
  62. package/ui/components/progress.css +502 -0
  63. package/ui/components/progress.js +931 -0
  64. package/ui/components/rail.css +152 -0
  65. package/ui/components/rating.css +257 -0
  66. package/ui/components/rating.js +508 -0
  67. package/ui/components/reset.css +476 -0
  68. package/ui/components/reveal.css +260 -0
  69. package/ui/components/search.css +431 -0
  70. package/ui/components/search.js +1505 -0
  71. package/ui/components/segment.css +824 -0
  72. package/ui/components/shape.css +143 -0
  73. package/ui/components/shape.js +921 -0
  74. package/ui/components/sidebar.css +537 -0
  75. package/ui/components/sidebar.js +1033 -0
  76. package/ui/components/site.css +184 -0
  77. package/ui/components/site.js +487 -0
  78. package/ui/components/state.js +708 -0
  79. package/ui/components/statistic.css +534 -0
  80. package/ui/components/step.css +566 -0
  81. package/ui/components/sticky.css +73 -0
  82. package/ui/components/sticky.js +959 -0
  83. package/ui/components/tab.css +89 -0
  84. package/ui/components/tab.js +952 -0
  85. package/ui/components/table.css +1108 -0
  86. package/ui/components/transition.css +1792 -0
  87. package/ui/components/transition.js +1095 -0
  88. package/ui/components/video.css +121 -0
  89. package/ui/components/video.js +532 -0
  90. package/ui/components/visibility.js +1311 -0
  91. package/ui/components/visit.js +517 -0
  92. package/ui/item.css +2 -2
  93. package/ui/layout.css +1 -1
  94. package/ui/themes/default/assets/fonts/brand-icons.eot +0 -0
  95. package/ui/themes/default/assets/fonts/brand-icons.svg +1008 -0
  96. package/ui/themes/default/assets/fonts/brand-icons.ttf +0 -0
  97. package/ui/themes/default/assets/fonts/brand-icons.woff +0 -0
  98. package/ui/themes/default/assets/fonts/brand-icons.woff2 +0 -0
  99. package/ui/themes/default/assets/fonts/icons.eot +0 -0
  100. package/ui/themes/default/assets/fonts/icons.otf +0 -0
  101. package/ui/themes/default/assets/fonts/icons.svg +1518 -0
  102. package/ui/themes/default/assets/fonts/icons.ttf +0 -0
  103. package/ui/themes/default/assets/fonts/icons.woff +0 -0
  104. package/ui/themes/default/assets/fonts/icons.woff2 +0 -0
  105. package/ui/themes/default/assets/fonts/outline-icons.eot +0 -0
  106. package/ui/themes/default/assets/fonts/outline-icons.svg +366 -0
  107. package/ui/themes/default/assets/fonts/outline-icons.ttf +0 -0
  108. package/ui/themes/default/assets/fonts/outline-icons.woff +0 -0
  109. package/ui/themes/default/assets/fonts/outline-icons.woff2 +0 -0
  110. package/ui/themes/default/assets/images/flags.png +0 -0
@@ -0,0 +1,1706 @@
1
+ /*!
2
+ * # Semantic UI 2.4.1 - Form Validation
3
+ * http://github.com/semantic-org/semantic-ui/
4
+ *
5
+ *
6
+ * Released under the MIT license
7
+ * http://opensource.org/licenses/MIT
8
+ *
9
+ */
10
+
11
+ ;(function ($, window, document, undefined) {
12
+
13
+ 'use strict';
14
+
15
+ window = (typeof window != 'undefined' && window.Math == Math)
16
+ ? window
17
+ : (typeof self != 'undefined' && self.Math == Math)
18
+ ? self
19
+ : Function('return this')()
20
+ ;
21
+
22
+ $.fn.form = function(parameters) {
23
+ var
24
+ $allModules = $(this),
25
+ moduleSelector = $allModules.selector || '',
26
+
27
+ time = new Date().getTime(),
28
+ performance = [],
29
+
30
+ query = arguments[0],
31
+ legacyParameters = arguments[1],
32
+ methodInvoked = (typeof query == 'string'),
33
+ queryArguments = [].slice.call(arguments, 1),
34
+ returnedValue
35
+ ;
36
+ $allModules
37
+ .each(function() {
38
+ var
39
+ $module = $(this),
40
+ element = this,
41
+
42
+ formErrors = [],
43
+ keyHeldDown = false,
44
+
45
+ // set at run-time
46
+ $field,
47
+ $group,
48
+ $message,
49
+ $prompt,
50
+ $submit,
51
+ $clear,
52
+ $reset,
53
+
54
+ settings,
55
+ validation,
56
+
57
+ metadata,
58
+ selector,
59
+ className,
60
+ regExp,
61
+ error,
62
+
63
+ namespace,
64
+ moduleNamespace,
65
+ eventNamespace,
66
+
67
+ instance,
68
+ module
69
+ ;
70
+
71
+ module = {
72
+
73
+ initialize: function() {
74
+
75
+ // settings grabbed at run time
76
+ module.get.settings();
77
+ if(methodInvoked) {
78
+ if(instance === undefined) {
79
+ module.instantiate();
80
+ }
81
+ module.invoke(query);
82
+ }
83
+ else {
84
+ if(instance !== undefined) {
85
+ instance.invoke('destroy');
86
+ }
87
+ module.verbose('Initializing form validation', $module, settings);
88
+ module.bindEvents();
89
+ module.set.defaults();
90
+ module.instantiate();
91
+ }
92
+ },
93
+
94
+ instantiate: function() {
95
+ module.verbose('Storing instance of module', module);
96
+ instance = module;
97
+ $module
98
+ .data(moduleNamespace, module)
99
+ ;
100
+ },
101
+
102
+ destroy: function() {
103
+ module.verbose('Destroying previous module', instance);
104
+ module.removeEvents();
105
+ $module
106
+ .removeData(moduleNamespace)
107
+ ;
108
+ },
109
+
110
+ refresh: function() {
111
+ module.verbose('Refreshing selector cache');
112
+ $field = $module.find(selector.field);
113
+ $group = $module.find(selector.group);
114
+ $message = $module.find(selector.message);
115
+ $prompt = $module.find(selector.prompt);
116
+
117
+ $submit = $module.find(selector.submit);
118
+ $clear = $module.find(selector.clear);
119
+ $reset = $module.find(selector.reset);
120
+ },
121
+
122
+ submit: function() {
123
+ module.verbose('Submitting form', $module);
124
+ $module
125
+ .submit()
126
+ ;
127
+ },
128
+
129
+ attachEvents: function(selector, action) {
130
+ action = action || 'submit';
131
+ $(selector)
132
+ .on('click' + eventNamespace, function(event) {
133
+ module[action]();
134
+ event.preventDefault();
135
+ })
136
+ ;
137
+ },
138
+
139
+ bindEvents: function() {
140
+ module.verbose('Attaching form events');
141
+ $module
142
+ .on('submit' + eventNamespace, module.validate.form)
143
+ .on('blur' + eventNamespace, selector.field, module.event.field.blur)
144
+ .on('click' + eventNamespace, selector.submit, module.submit)
145
+ .on('click' + eventNamespace, selector.reset, module.reset)
146
+ .on('click' + eventNamespace, selector.clear, module.clear)
147
+ ;
148
+ if(settings.keyboardShortcuts) {
149
+ $module
150
+ .on('keydown' + eventNamespace, selector.field, module.event.field.keydown)
151
+ ;
152
+ }
153
+ $field
154
+ .each(function() {
155
+ var
156
+ $input = $(this),
157
+ type = $input.prop('type'),
158
+ inputEvent = module.get.changeEvent(type, $input)
159
+ ;
160
+ $(this)
161
+ .on(inputEvent + eventNamespace, module.event.field.change)
162
+ ;
163
+ })
164
+ ;
165
+ },
166
+
167
+ clear: function() {
168
+ $field
169
+ .each(function () {
170
+ var
171
+ $field = $(this),
172
+ $element = $field.parent(),
173
+ $fieldGroup = $field.closest($group),
174
+ $prompt = $fieldGroup.find(selector.prompt),
175
+ defaultValue = $field.data(metadata.defaultValue) || '',
176
+ isCheckbox = $element.is(selector.uiCheckbox),
177
+ isDropdown = $element.is(selector.uiDropdown),
178
+ isErrored = $fieldGroup.hasClass(className.error)
179
+ ;
180
+ if(isErrored) {
181
+ module.verbose('Resetting error on field', $fieldGroup);
182
+ $fieldGroup.removeClass(className.error);
183
+ $prompt.remove();
184
+ }
185
+ if(isDropdown) {
186
+ module.verbose('Resetting dropdown value', $element, defaultValue);
187
+ $element.dropdown('clear');
188
+ }
189
+ else if(isCheckbox) {
190
+ $field.prop('checked', false);
191
+ }
192
+ else {
193
+ module.verbose('Resetting field value', $field, defaultValue);
194
+ $field.val('');
195
+ }
196
+ })
197
+ ;
198
+ },
199
+
200
+ reset: function() {
201
+ $field
202
+ .each(function () {
203
+ var
204
+ $field = $(this),
205
+ $element = $field.parent(),
206
+ $fieldGroup = $field.closest($group),
207
+ $prompt = $fieldGroup.find(selector.prompt),
208
+ defaultValue = $field.data(metadata.defaultValue),
209
+ isCheckbox = $element.is(selector.uiCheckbox),
210
+ isDropdown = $element.is(selector.uiDropdown),
211
+ isErrored = $fieldGroup.hasClass(className.error)
212
+ ;
213
+ if(defaultValue === undefined) {
214
+ return;
215
+ }
216
+ if(isErrored) {
217
+ module.verbose('Resetting error on field', $fieldGroup);
218
+ $fieldGroup.removeClass(className.error);
219
+ $prompt.remove();
220
+ }
221
+ if(isDropdown) {
222
+ module.verbose('Resetting dropdown value', $element, defaultValue);
223
+ $element.dropdown('restore defaults');
224
+ }
225
+ else if(isCheckbox) {
226
+ module.verbose('Resetting checkbox value', $element, defaultValue);
227
+ $field.prop('checked', defaultValue);
228
+ }
229
+ else {
230
+ module.verbose('Resetting field value', $field, defaultValue);
231
+ $field.val(defaultValue);
232
+ }
233
+ })
234
+ ;
235
+ },
236
+
237
+ determine: {
238
+ isValid: function() {
239
+ var
240
+ allValid = true
241
+ ;
242
+ $.each(validation, function(fieldName, field) {
243
+ if( !( module.validate.field(field, fieldName, true) ) ) {
244
+ allValid = false;
245
+ }
246
+ });
247
+ return allValid;
248
+ }
249
+ },
250
+
251
+ is: {
252
+ bracketedRule: function(rule) {
253
+ return (rule.type && rule.type.match(settings.regExp.bracket));
254
+ },
255
+ shorthandFields: function(fields) {
256
+ var
257
+ fieldKeys = Object.keys(fields),
258
+ firstRule = fields[fieldKeys[0]]
259
+ ;
260
+ return module.is.shorthandRules(firstRule);
261
+ },
262
+ // duck type rule test
263
+ shorthandRules: function(rules) {
264
+ return (typeof rules == 'string' || $.isArray(rules));
265
+ },
266
+ empty: function($field) {
267
+ if(!$field || $field.length === 0) {
268
+ return true;
269
+ }
270
+ else if($field.is('input[type="checkbox"]')) {
271
+ return !$field.is(':checked');
272
+ }
273
+ else {
274
+ return module.is.blank($field);
275
+ }
276
+ },
277
+ blank: function($field) {
278
+ return $.trim($field.val()) === '';
279
+ },
280
+ valid: function(field) {
281
+ var
282
+ allValid = true
283
+ ;
284
+ if(field) {
285
+ module.verbose('Checking if field is valid', field);
286
+ return module.validate.field(validation[field], field, false);
287
+ }
288
+ else {
289
+ module.verbose('Checking if form is valid');
290
+ $.each(validation, function(fieldName, field) {
291
+ if( !module.is.valid(fieldName) ) {
292
+ allValid = false;
293
+ }
294
+ });
295
+ return allValid;
296
+ }
297
+ }
298
+ },
299
+
300
+ removeEvents: function() {
301
+ $module
302
+ .off(eventNamespace)
303
+ ;
304
+ $field
305
+ .off(eventNamespace)
306
+ ;
307
+ $submit
308
+ .off(eventNamespace)
309
+ ;
310
+ $field
311
+ .off(eventNamespace)
312
+ ;
313
+ },
314
+
315
+ event: {
316
+ field: {
317
+ keydown: function(event) {
318
+ var
319
+ $field = $(this),
320
+ key = event.which,
321
+ isInput = $field.is(selector.input),
322
+ isCheckbox = $field.is(selector.checkbox),
323
+ isInDropdown = ($field.closest(selector.uiDropdown).length > 0),
324
+ keyCode = {
325
+ enter : 13,
326
+ escape : 27
327
+ }
328
+ ;
329
+ if( key == keyCode.escape) {
330
+ module.verbose('Escape key pressed blurring field');
331
+ $field
332
+ .blur()
333
+ ;
334
+ }
335
+ if(!event.ctrlKey && key == keyCode.enter && isInput && !isInDropdown && !isCheckbox) {
336
+ if(!keyHeldDown) {
337
+ $field
338
+ .one('keyup' + eventNamespace, module.event.field.keyup)
339
+ ;
340
+ module.submit();
341
+ module.debug('Enter pressed on input submitting form');
342
+ }
343
+ keyHeldDown = true;
344
+ }
345
+ },
346
+ keyup: function() {
347
+ keyHeldDown = false;
348
+ },
349
+ blur: function(event) {
350
+ var
351
+ $field = $(this),
352
+ $fieldGroup = $field.closest($group),
353
+ validationRules = module.get.validation($field)
354
+ ;
355
+ if( $fieldGroup.hasClass(className.error) ) {
356
+ module.debug('Revalidating field', $field, validationRules);
357
+ if(validationRules) {
358
+ module.validate.field( validationRules );
359
+ }
360
+ }
361
+ else if(settings.on == 'blur') {
362
+ if(validationRules) {
363
+ module.validate.field( validationRules );
364
+ }
365
+ }
366
+ },
367
+ change: function(event) {
368
+ var
369
+ $field = $(this),
370
+ $fieldGroup = $field.closest($group),
371
+ validationRules = module.get.validation($field)
372
+ ;
373
+ if(validationRules && (settings.on == 'change' || ( $fieldGroup.hasClass(className.error) && settings.revalidate) )) {
374
+ clearTimeout(module.timer);
375
+ module.timer = setTimeout(function() {
376
+ module.debug('Revalidating field', $field, module.get.validation($field));
377
+ module.validate.field( validationRules );
378
+ }, settings.delay);
379
+ }
380
+ }
381
+ }
382
+
383
+ },
384
+
385
+ get: {
386
+ ancillaryValue: function(rule) {
387
+ if(!rule.type || (!rule.value && !module.is.bracketedRule(rule))) {
388
+ return false;
389
+ }
390
+ return (rule.value !== undefined)
391
+ ? rule.value
392
+ : rule.type.match(settings.regExp.bracket)[1] + ''
393
+ ;
394
+ },
395
+ ruleName: function(rule) {
396
+ if( module.is.bracketedRule(rule) ) {
397
+ return rule.type.replace(rule.type.match(settings.regExp.bracket)[0], '');
398
+ }
399
+ return rule.type;
400
+ },
401
+ changeEvent: function(type, $input) {
402
+ if(type == 'checkbox' || type == 'radio' || type == 'hidden' || $input.is('select')) {
403
+ return 'change';
404
+ }
405
+ else {
406
+ return module.get.inputEvent();
407
+ }
408
+ },
409
+ inputEvent: function() {
410
+ return (document.createElement('input').oninput !== undefined)
411
+ ? 'input'
412
+ : (document.createElement('input').onpropertychange !== undefined)
413
+ ? 'propertychange'
414
+ : 'keyup'
415
+ ;
416
+ },
417
+ fieldsFromShorthand: function(fields) {
418
+ var
419
+ fullFields = {}
420
+ ;
421
+ $.each(fields, function(name, rules) {
422
+ if(typeof rules == 'string') {
423
+ rules = [rules];
424
+ }
425
+ fullFields[name] = {
426
+ rules: []
427
+ };
428
+ $.each(rules, function(index, rule) {
429
+ fullFields[name].rules.push({ type: rule });
430
+ });
431
+ });
432
+ return fullFields;
433
+ },
434
+ prompt: function(rule, field) {
435
+ var
436
+ ruleName = module.get.ruleName(rule),
437
+ ancillary = module.get.ancillaryValue(rule),
438
+ $field = module.get.field(field.identifier),
439
+ value = $field.val(),
440
+ prompt = $.isFunction(rule.prompt)
441
+ ? rule.prompt(value)
442
+ : rule.prompt || settings.prompt[ruleName] || settings.text.unspecifiedRule,
443
+ requiresValue = (prompt.search('{value}') !== -1),
444
+ requiresName = (prompt.search('{name}') !== -1),
445
+ $label,
446
+ name
447
+ ;
448
+ if(requiresValue) {
449
+ prompt = prompt.replace('{value}', $field.val());
450
+ }
451
+ if(requiresName) {
452
+ $label = $field.closest(selector.group).find('label').eq(0);
453
+ name = ($label.length == 1)
454
+ ? $label.text()
455
+ : $field.prop('placeholder') || settings.text.unspecifiedField
456
+ ;
457
+ prompt = prompt.replace('{name}', name);
458
+ }
459
+ prompt = prompt.replace('{identifier}', field.identifier);
460
+ prompt = prompt.replace('{ruleValue}', ancillary);
461
+ if(!rule.prompt) {
462
+ module.verbose('Using default validation prompt for type', prompt, ruleName);
463
+ }
464
+ return prompt;
465
+ },
466
+ settings: function() {
467
+ if($.isPlainObject(parameters)) {
468
+ var
469
+ keys = Object.keys(parameters),
470
+ isLegacySettings = (keys.length > 0)
471
+ ? (parameters[keys[0]].identifier !== undefined && parameters[keys[0]].rules !== undefined)
472
+ : false,
473
+ ruleKeys
474
+ ;
475
+ if(isLegacySettings) {
476
+ // 1.x (ducktyped)
477
+ settings = $.extend(true, {}, $.fn.form.settings, legacyParameters);
478
+ validation = $.extend({}, $.fn.form.settings.defaults, parameters);
479
+ module.error(settings.error.oldSyntax, element);
480
+ module.verbose('Extending settings from legacy parameters', validation, settings);
481
+ }
482
+ else {
483
+ // 2.x
484
+ if(parameters.fields && module.is.shorthandFields(parameters.fields)) {
485
+ parameters.fields = module.get.fieldsFromShorthand(parameters.fields);
486
+ }
487
+ settings = $.extend(true, {}, $.fn.form.settings, parameters);
488
+ validation = $.extend({}, $.fn.form.settings.defaults, settings.fields);
489
+ module.verbose('Extending settings', validation, settings);
490
+ }
491
+ }
492
+ else {
493
+ settings = $.fn.form.settings;
494
+ validation = $.fn.form.settings.defaults;
495
+ module.verbose('Using default form validation', validation, settings);
496
+ }
497
+
498
+ // shorthand
499
+ namespace = settings.namespace;
500
+ metadata = settings.metadata;
501
+ selector = settings.selector;
502
+ className = settings.className;
503
+ regExp = settings.regExp;
504
+ error = settings.error;
505
+ moduleNamespace = 'module-' + namespace;
506
+ eventNamespace = '.' + namespace;
507
+
508
+ // grab instance
509
+ instance = $module.data(moduleNamespace);
510
+
511
+ // refresh selector cache
512
+ module.refresh();
513
+ },
514
+ field: function(identifier) {
515
+ module.verbose('Finding field with identifier', identifier);
516
+ identifier = module.escape.string(identifier);
517
+ if($field.filter('#' + identifier).length > 0 ) {
518
+ return $field.filter('#' + identifier);
519
+ }
520
+ else if( $field.filter('[name="' + identifier +'"]').length > 0 ) {
521
+ return $field.filter('[name="' + identifier +'"]');
522
+ }
523
+ else if( $field.filter('[name="' + identifier +'[]"]').length > 0 ) {
524
+ return $field.filter('[name="' + identifier +'[]"]');
525
+ }
526
+ else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').length > 0 ) {
527
+ return $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]');
528
+ }
529
+ return $('<input/>');
530
+ },
531
+ fields: function(fields) {
532
+ var
533
+ $fields = $()
534
+ ;
535
+ $.each(fields, function(index, name) {
536
+ $fields = $fields.add( module.get.field(name) );
537
+ });
538
+ return $fields;
539
+ },
540
+ validation: function($field) {
541
+ var
542
+ fieldValidation,
543
+ identifier
544
+ ;
545
+ if(!validation) {
546
+ return false;
547
+ }
548
+ $.each(validation, function(fieldName, field) {
549
+ identifier = field.identifier || fieldName;
550
+ if( module.get.field(identifier)[0] == $field[0] ) {
551
+ field.identifier = identifier;
552
+ fieldValidation = field;
553
+ }
554
+ });
555
+ return fieldValidation || false;
556
+ },
557
+ value: function (field) {
558
+ var
559
+ fields = [],
560
+ results
561
+ ;
562
+ fields.push(field);
563
+ results = module.get.values.call(element, fields);
564
+ return results[field];
565
+ },
566
+ values: function (fields) {
567
+ var
568
+ $fields = $.isArray(fields)
569
+ ? module.get.fields(fields)
570
+ : $field,
571
+ values = {}
572
+ ;
573
+ $fields.each(function(index, field) {
574
+ var
575
+ $field = $(field),
576
+ type = $field.prop('type'),
577
+ name = $field.prop('name'),
578
+ value = $field.val(),
579
+ isCheckbox = $field.is(selector.checkbox),
580
+ isRadio = $field.is(selector.radio),
581
+ isMultiple = (name.indexOf('[]') !== -1),
582
+ isChecked = (isCheckbox)
583
+ ? $field.is(':checked')
584
+ : false
585
+ ;
586
+ if(name) {
587
+ if(isMultiple) {
588
+ name = name.replace('[]', '');
589
+ if(!values[name]) {
590
+ values[name] = [];
591
+ }
592
+ if(isCheckbox) {
593
+ if(isChecked) {
594
+ values[name].push(value || true);
595
+ }
596
+ else {
597
+ values[name].push(false);
598
+ }
599
+ }
600
+ else {
601
+ values[name].push(value);
602
+ }
603
+ }
604
+ else {
605
+ if(isRadio) {
606
+ if(values[name] === undefined || values[name] == false) {
607
+ values[name] = (isChecked)
608
+ ? value || true
609
+ : false
610
+ ;
611
+ }
612
+ }
613
+ else if(isCheckbox) {
614
+ if(isChecked) {
615
+ values[name] = value || true;
616
+ }
617
+ else {
618
+ values[name] = false;
619
+ }
620
+ }
621
+ else {
622
+ values[name] = value;
623
+ }
624
+ }
625
+ }
626
+ });
627
+ return values;
628
+ }
629
+ },
630
+
631
+ has: {
632
+
633
+ field: function(identifier) {
634
+ module.verbose('Checking for existence of a field with identifier', identifier);
635
+ identifier = module.escape.string(identifier);
636
+ if(typeof identifier !== 'string') {
637
+ module.error(error.identifier, identifier);
638
+ }
639
+ if($field.filter('#' + identifier).length > 0 ) {
640
+ return true;
641
+ }
642
+ else if( $field.filter('[name="' + identifier +'"]').length > 0 ) {
643
+ return true;
644
+ }
645
+ else if( $field.filter('[data-' + metadata.validate + '="'+ identifier +'"]').length > 0 ) {
646
+ return true;
647
+ }
648
+ return false;
649
+ }
650
+
651
+ },
652
+
653
+ escape: {
654
+ string: function(text) {
655
+ text = String(text);
656
+ return text.replace(regExp.escape, '\\$&');
657
+ }
658
+ },
659
+
660
+ add: {
661
+ // alias
662
+ rule: function(name, rules) {
663
+ module.add.field(name, rules);
664
+ },
665
+ field: function(name, rules) {
666
+ var
667
+ newValidation = {}
668
+ ;
669
+ if(module.is.shorthandRules(rules)) {
670
+ rules = $.isArray(rules)
671
+ ? rules
672
+ : [rules]
673
+ ;
674
+ newValidation[name] = {
675
+ rules: []
676
+ };
677
+ $.each(rules, function(index, rule) {
678
+ newValidation[name].rules.push({ type: rule });
679
+ });
680
+ }
681
+ else {
682
+ newValidation[name] = rules;
683
+ }
684
+ validation = $.extend({}, validation, newValidation);
685
+ module.debug('Adding rules', newValidation, validation);
686
+ },
687
+ fields: function(fields) {
688
+ var
689
+ newValidation
690
+ ;
691
+ if(fields && module.is.shorthandFields(fields)) {
692
+ newValidation = module.get.fieldsFromShorthand(fields);
693
+ }
694
+ else {
695
+ newValidation = fields;
696
+ }
697
+ validation = $.extend({}, validation, newValidation);
698
+ },
699
+ prompt: function(identifier, errors) {
700
+ var
701
+ $field = module.get.field(identifier),
702
+ $fieldGroup = $field.closest($group),
703
+ $prompt = $fieldGroup.children(selector.prompt),
704
+ promptExists = ($prompt.length !== 0)
705
+ ;
706
+ errors = (typeof errors == 'string')
707
+ ? [errors]
708
+ : errors
709
+ ;
710
+ module.verbose('Adding field error state', identifier);
711
+ $fieldGroup
712
+ .addClass(className.error)
713
+ ;
714
+ if(settings.inline) {
715
+ if(!promptExists) {
716
+ $prompt = settings.templates.prompt(errors);
717
+ $prompt
718
+ .appendTo($fieldGroup)
719
+ ;
720
+ }
721
+ $prompt
722
+ .html(errors[0])
723
+ ;
724
+ if(!promptExists) {
725
+ if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
726
+ module.verbose('Displaying error with css transition', settings.transition);
727
+ $prompt.transition(settings.transition + ' in', settings.duration);
728
+ }
729
+ else {
730
+ module.verbose('Displaying error with fallback javascript animation');
731
+ $prompt
732
+ .fadeIn(settings.duration)
733
+ ;
734
+ }
735
+ }
736
+ else {
737
+ module.verbose('Inline errors are disabled, no inline error added', identifier);
738
+ }
739
+ }
740
+ },
741
+ errors: function(errors) {
742
+ module.debug('Adding form error messages', errors);
743
+ module.set.error();
744
+ $message
745
+ .html( settings.templates.error(errors) )
746
+ ;
747
+ }
748
+ },
749
+
750
+ remove: {
751
+ rule: function(field, rule) {
752
+ var
753
+ rules = $.isArray(rule)
754
+ ? rule
755
+ : [rule]
756
+ ;
757
+ if(rule == undefined) {
758
+ module.debug('Removed all rules');
759
+ validation[field].rules = [];
760
+ return;
761
+ }
762
+ if(validation[field] == undefined || !$.isArray(validation[field].rules)) {
763
+ return;
764
+ }
765
+ $.each(validation[field].rules, function(index, rule) {
766
+ if(rules.indexOf(rule.type) !== -1) {
767
+ module.debug('Removed rule', rule.type);
768
+ validation[field].rules.splice(index, 1);
769
+ }
770
+ });
771
+ },
772
+ field: function(field) {
773
+ var
774
+ fields = $.isArray(field)
775
+ ? field
776
+ : [field]
777
+ ;
778
+ $.each(fields, function(index, field) {
779
+ module.remove.rule(field);
780
+ });
781
+ },
782
+ // alias
783
+ rules: function(field, rules) {
784
+ if($.isArray(field)) {
785
+ $.each(fields, function(index, field) {
786
+ module.remove.rule(field, rules);
787
+ });
788
+ }
789
+ else {
790
+ module.remove.rule(field, rules);
791
+ }
792
+ },
793
+ fields: function(fields) {
794
+ module.remove.field(fields);
795
+ },
796
+ prompt: function(identifier) {
797
+ var
798
+ $field = module.get.field(identifier),
799
+ $fieldGroup = $field.closest($group),
800
+ $prompt = $fieldGroup.children(selector.prompt)
801
+ ;
802
+ $fieldGroup
803
+ .removeClass(className.error)
804
+ ;
805
+ if(settings.inline && $prompt.is(':visible')) {
806
+ module.verbose('Removing prompt for field', identifier);
807
+ if(settings.transition && $.fn.transition !== undefined && $module.transition('is supported')) {
808
+ $prompt.transition(settings.transition + ' out', settings.duration, function() {
809
+ $prompt.remove();
810
+ });
811
+ }
812
+ else {
813
+ $prompt
814
+ .fadeOut(settings.duration, function(){
815
+ $prompt.remove();
816
+ })
817
+ ;
818
+ }
819
+ }
820
+ }
821
+ },
822
+
823
+ set: {
824
+ success: function() {
825
+ $module
826
+ .removeClass(className.error)
827
+ .addClass(className.success)
828
+ ;
829
+ },
830
+ defaults: function () {
831
+ $field
832
+ .each(function () {
833
+ var
834
+ $field = $(this),
835
+ isCheckbox = ($field.filter(selector.checkbox).length > 0),
836
+ value = (isCheckbox)
837
+ ? $field.is(':checked')
838
+ : $field.val()
839
+ ;
840
+ $field.data(metadata.defaultValue, value);
841
+ })
842
+ ;
843
+ },
844
+ error: function() {
845
+ $module
846
+ .removeClass(className.success)
847
+ .addClass(className.error)
848
+ ;
849
+ },
850
+ value: function (field, value) {
851
+ var
852
+ fields = {}
853
+ ;
854
+ fields[field] = value;
855
+ return module.set.values.call(element, fields);
856
+ },
857
+ values: function (fields) {
858
+ if($.isEmptyObject(fields)) {
859
+ return;
860
+ }
861
+ $.each(fields, function(key, value) {
862
+ var
863
+ $field = module.get.field(key),
864
+ $element = $field.parent(),
865
+ isMultiple = $.isArray(value),
866
+ isCheckbox = $element.is(selector.uiCheckbox),
867
+ isDropdown = $element.is(selector.uiDropdown),
868
+ isRadio = ($field.is(selector.radio) && isCheckbox),
869
+ fieldExists = ($field.length > 0),
870
+ $multipleField
871
+ ;
872
+ if(fieldExists) {
873
+ if(isMultiple && isCheckbox) {
874
+ module.verbose('Selecting multiple', value, $field);
875
+ $element.checkbox('uncheck');
876
+ $.each(value, function(index, value) {
877
+ $multipleField = $field.filter('[value="' + value + '"]');
878
+ $element = $multipleField.parent();
879
+ if($multipleField.length > 0) {
880
+ $element.checkbox('check');
881
+ }
882
+ });
883
+ }
884
+ else if(isRadio) {
885
+ module.verbose('Selecting radio value', value, $field);
886
+ $field.filter('[value="' + value + '"]')
887
+ .parent(selector.uiCheckbox)
888
+ .checkbox('check')
889
+ ;
890
+ }
891
+ else if(isCheckbox) {
892
+ module.verbose('Setting checkbox value', value, $element);
893
+ if(value === true) {
894
+ $element.checkbox('check');
895
+ }
896
+ else {
897
+ $element.checkbox('uncheck');
898
+ }
899
+ }
900
+ else if(isDropdown) {
901
+ module.verbose('Setting dropdown value', value, $element);
902
+ $element.dropdown('set selected', value);
903
+ }
904
+ else {
905
+ module.verbose('Setting field value', value, $field);
906
+ $field.val(value);
907
+ }
908
+ }
909
+ });
910
+ }
911
+ },
912
+
913
+ validate: {
914
+
915
+ form: function(event, ignoreCallbacks) {
916
+ var
917
+ values = module.get.values(),
918
+ apiRequest
919
+ ;
920
+
921
+ // input keydown event will fire submit repeatedly by browser default
922
+ if(keyHeldDown) {
923
+ return false;
924
+ }
925
+
926
+ // reset errors
927
+ formErrors = [];
928
+ if( module.determine.isValid() ) {
929
+ module.debug('Form has no validation errors, submitting');
930
+ module.set.success();
931
+ if(ignoreCallbacks !== true) {
932
+ return settings.onSuccess.call(element, event, values);
933
+ }
934
+ }
935
+ else {
936
+ module.debug('Form has errors');
937
+ module.set.error();
938
+ if(!settings.inline) {
939
+ module.add.errors(formErrors);
940
+ }
941
+ // prevent ajax submit
942
+ if($module.data('moduleApi') !== undefined) {
943
+ event.stopImmediatePropagation();
944
+ }
945
+ if(ignoreCallbacks !== true) {
946
+ return settings.onFailure.call(element, formErrors, values);
947
+ }
948
+ }
949
+ },
950
+
951
+ // takes a validation object and returns whether field passes validation
952
+ field: function(field, fieldName, showErrors) {
953
+ showErrors = (showErrors !== undefined)
954
+ ? showErrors
955
+ : true
956
+ ;
957
+ if(typeof field == 'string') {
958
+ module.verbose('Validating field', field);
959
+ fieldName = field;
960
+ field = validation[field];
961
+ }
962
+ var
963
+ identifier = field.identifier || fieldName,
964
+ $field = module.get.field(identifier),
965
+ $dependsField = (field.depends)
966
+ ? module.get.field(field.depends)
967
+ : false,
968
+ fieldValid = true,
969
+ fieldErrors = []
970
+ ;
971
+ if(!field.identifier) {
972
+ module.debug('Using field name as identifier', identifier);
973
+ field.identifier = identifier;
974
+ }
975
+ if($field.prop('disabled')) {
976
+ module.debug('Field is disabled. Skipping', identifier);
977
+ fieldValid = true;
978
+ }
979
+ else if(field.optional && module.is.blank($field)){
980
+ module.debug('Field is optional and blank. Skipping', identifier);
981
+ fieldValid = true;
982
+ }
983
+ else if(field.depends && module.is.empty($dependsField)) {
984
+ module.debug('Field depends on another value that is not present or empty. Skipping', $dependsField);
985
+ fieldValid = true;
986
+ }
987
+ else if(field.rules !== undefined) {
988
+ $.each(field.rules, function(index, rule) {
989
+ if( module.has.field(identifier) && !( module.validate.rule(field, rule) ) ) {
990
+ module.debug('Field is invalid', identifier, rule.type);
991
+ fieldErrors.push(module.get.prompt(rule, field));
992
+ fieldValid = false;
993
+ }
994
+ });
995
+ }
996
+ if(fieldValid) {
997
+ if(showErrors) {
998
+ module.remove.prompt(identifier, fieldErrors);
999
+ settings.onValid.call($field);
1000
+ }
1001
+ }
1002
+ else {
1003
+ if(showErrors) {
1004
+ formErrors = formErrors.concat(fieldErrors);
1005
+ module.add.prompt(identifier, fieldErrors);
1006
+ settings.onInvalid.call($field, fieldErrors);
1007
+ }
1008
+ return false;
1009
+ }
1010
+ return true;
1011
+ },
1012
+
1013
+ // takes validation rule and returns whether field passes rule
1014
+ rule: function(field, rule) {
1015
+ var
1016
+ $field = module.get.field(field.identifier),
1017
+ type = rule.type,
1018
+ value = $field.val(),
1019
+ isValid = true,
1020
+ ancillary = module.get.ancillaryValue(rule),
1021
+ ruleName = module.get.ruleName(rule),
1022
+ ruleFunction = settings.rules[ruleName]
1023
+ ;
1024
+ if( !$.isFunction(ruleFunction) ) {
1025
+ module.error(error.noRule, ruleName);
1026
+ return;
1027
+ }
1028
+ // cast to string avoiding encoding special values
1029
+ value = (value === undefined || value === '' || value === null)
1030
+ ? ''
1031
+ : $.trim(value + '')
1032
+ ;
1033
+ return ruleFunction.call($field, value, ancillary);
1034
+ }
1035
+ },
1036
+
1037
+ setting: function(name, value) {
1038
+ if( $.isPlainObject(name) ) {
1039
+ $.extend(true, settings, name);
1040
+ }
1041
+ else if(value !== undefined) {
1042
+ settings[name] = value;
1043
+ }
1044
+ else {
1045
+ return settings[name];
1046
+ }
1047
+ },
1048
+ internal: function(name, value) {
1049
+ if( $.isPlainObject(name) ) {
1050
+ $.extend(true, module, name);
1051
+ }
1052
+ else if(value !== undefined) {
1053
+ module[name] = value;
1054
+ }
1055
+ else {
1056
+ return module[name];
1057
+ }
1058
+ },
1059
+ debug: function() {
1060
+ if(!settings.silent && settings.debug) {
1061
+ if(settings.performance) {
1062
+ module.performance.log(arguments);
1063
+ }
1064
+ else {
1065
+ module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
1066
+ module.debug.apply(console, arguments);
1067
+ }
1068
+ }
1069
+ },
1070
+ verbose: function() {
1071
+ if(!settings.silent && settings.verbose && settings.debug) {
1072
+ if(settings.performance) {
1073
+ module.performance.log(arguments);
1074
+ }
1075
+ else {
1076
+ module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
1077
+ module.verbose.apply(console, arguments);
1078
+ }
1079
+ }
1080
+ },
1081
+ error: function() {
1082
+ if(!settings.silent) {
1083
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
1084
+ module.error.apply(console, arguments);
1085
+ }
1086
+ },
1087
+ performance: {
1088
+ log: function(message) {
1089
+ var
1090
+ currentTime,
1091
+ executionTime,
1092
+ previousTime
1093
+ ;
1094
+ if(settings.performance) {
1095
+ currentTime = new Date().getTime();
1096
+ previousTime = time || currentTime;
1097
+ executionTime = currentTime - previousTime;
1098
+ time = currentTime;
1099
+ performance.push({
1100
+ 'Name' : message[0],
1101
+ 'Arguments' : [].slice.call(message, 1) || '',
1102
+ 'Element' : element,
1103
+ 'Execution Time' : executionTime
1104
+ });
1105
+ }
1106
+ clearTimeout(module.performance.timer);
1107
+ module.performance.timer = setTimeout(module.performance.display, 500);
1108
+ },
1109
+ display: function() {
1110
+ var
1111
+ title = settings.name + ':',
1112
+ totalTime = 0
1113
+ ;
1114
+ time = false;
1115
+ clearTimeout(module.performance.timer);
1116
+ $.each(performance, function(index, data) {
1117
+ totalTime += data['Execution Time'];
1118
+ });
1119
+ title += ' ' + totalTime + 'ms';
1120
+ if(moduleSelector) {
1121
+ title += ' \'' + moduleSelector + '\'';
1122
+ }
1123
+ if($allModules.length > 1) {
1124
+ title += ' ' + '(' + $allModules.length + ')';
1125
+ }
1126
+ if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
1127
+ console.groupCollapsed(title);
1128
+ if(console.table) {
1129
+ console.table(performance);
1130
+ }
1131
+ else {
1132
+ $.each(performance, function(index, data) {
1133
+ console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
1134
+ });
1135
+ }
1136
+ console.groupEnd();
1137
+ }
1138
+ performance = [];
1139
+ }
1140
+ },
1141
+ invoke: function(query, passedArguments, context) {
1142
+ var
1143
+ object = instance,
1144
+ maxDepth,
1145
+ found,
1146
+ response
1147
+ ;
1148
+ passedArguments = passedArguments || queryArguments;
1149
+ context = element || context;
1150
+ if(typeof query == 'string' && object !== undefined) {
1151
+ query = query.split(/[\. ]/);
1152
+ maxDepth = query.length - 1;
1153
+ $.each(query, function(depth, value) {
1154
+ var camelCaseValue = (depth != maxDepth)
1155
+ ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
1156
+ : query
1157
+ ;
1158
+ if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
1159
+ object = object[camelCaseValue];
1160
+ }
1161
+ else if( object[camelCaseValue] !== undefined ) {
1162
+ found = object[camelCaseValue];
1163
+ return false;
1164
+ }
1165
+ else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
1166
+ object = object[value];
1167
+ }
1168
+ else if( object[value] !== undefined ) {
1169
+ found = object[value];
1170
+ return false;
1171
+ }
1172
+ else {
1173
+ return false;
1174
+ }
1175
+ });
1176
+ }
1177
+ if( $.isFunction( found ) ) {
1178
+ response = found.apply(context, passedArguments);
1179
+ }
1180
+ else if(found !== undefined) {
1181
+ response = found;
1182
+ }
1183
+ if($.isArray(returnedValue)) {
1184
+ returnedValue.push(response);
1185
+ }
1186
+ else if(returnedValue !== undefined) {
1187
+ returnedValue = [returnedValue, response];
1188
+ }
1189
+ else if(response !== undefined) {
1190
+ returnedValue = response;
1191
+ }
1192
+ return found;
1193
+ }
1194
+ };
1195
+ module.initialize();
1196
+ })
1197
+ ;
1198
+
1199
+ return (returnedValue !== undefined)
1200
+ ? returnedValue
1201
+ : this
1202
+ ;
1203
+ };
1204
+
1205
+ $.fn.form.settings = {
1206
+
1207
+ name : 'Form',
1208
+ namespace : 'form',
1209
+
1210
+ debug : false,
1211
+ verbose : false,
1212
+ performance : true,
1213
+
1214
+ fields : false,
1215
+
1216
+ keyboardShortcuts : true,
1217
+ on : 'submit',
1218
+ inline : false,
1219
+
1220
+ delay : 200,
1221
+ revalidate : true,
1222
+
1223
+ transition : 'scale',
1224
+ duration : 200,
1225
+
1226
+ onValid : function() {},
1227
+ onInvalid : function() {},
1228
+ onSuccess : function() { return true; },
1229
+ onFailure : function() { return false; },
1230
+
1231
+ metadata : {
1232
+ defaultValue : 'default',
1233
+ validate : 'validate'
1234
+ },
1235
+
1236
+ regExp: {
1237
+ htmlID : /^[a-zA-Z][\w:.-]*$/g,
1238
+ bracket : /\[(.*)\]/i,
1239
+ decimal : /^\d+\.?\d*$/,
1240
+ email : /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,
1241
+ escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
1242
+ flags : /^\/(.*)\/(.*)?/,
1243
+ integer : /^\-?\d+$/,
1244
+ number : /^\-?\d*(\.\d+)?$/,
1245
+ url : /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/i
1246
+ },
1247
+
1248
+ text: {
1249
+ unspecifiedRule : 'Please enter a valid value',
1250
+ unspecifiedField : 'This field'
1251
+ },
1252
+
1253
+ prompt: {
1254
+ empty : '{name} must have a value',
1255
+ checked : '{name} must be checked',
1256
+ email : '{name} must be a valid e-mail',
1257
+ url : '{name} must be a valid url',
1258
+ regExp : '{name} is not formatted correctly',
1259
+ integer : '{name} must be an integer',
1260
+ decimal : '{name} must be a decimal number',
1261
+ number : '{name} must be set to a number',
1262
+ is : '{name} must be "{ruleValue}"',
1263
+ isExactly : '{name} must be exactly "{ruleValue}"',
1264
+ not : '{name} cannot be set to "{ruleValue}"',
1265
+ notExactly : '{name} cannot be set to exactly "{ruleValue}"',
1266
+ contain : '{name} must contain "{ruleValue}"',
1267
+ containExactly : '{name} must contain exactly "{ruleValue}"',
1268
+ doesntContain : '{name} cannot contain "{ruleValue}"',
1269
+ doesntContainExactly : '{name} cannot contain exactly "{ruleValue}"',
1270
+ minLength : '{name} must be at least {ruleValue} characters',
1271
+ length : '{name} must be at least {ruleValue} characters',
1272
+ exactLength : '{name} must be exactly {ruleValue} characters',
1273
+ maxLength : '{name} cannot be longer than {ruleValue} characters',
1274
+ match : '{name} must match {ruleValue} field',
1275
+ different : '{name} must have a different value than {ruleValue} field',
1276
+ creditCard : '{name} must be a valid credit card number',
1277
+ minCount : '{name} must have at least {ruleValue} choices',
1278
+ exactCount : '{name} must have exactly {ruleValue} choices',
1279
+ maxCount : '{name} must have {ruleValue} or less choices'
1280
+ },
1281
+
1282
+ selector : {
1283
+ checkbox : 'input[type="checkbox"], input[type="radio"]',
1284
+ clear : '.clear',
1285
+ field : 'input, textarea, select',
1286
+ group : '.field',
1287
+ input : 'input',
1288
+ message : '.error.message',
1289
+ prompt : '.prompt.label',
1290
+ radio : 'input[type="radio"]',
1291
+ reset : '.reset:not([type="reset"])',
1292
+ submit : '.submit:not([type="submit"])',
1293
+ uiCheckbox : '.ui.checkbox',
1294
+ uiDropdown : '.ui.dropdown'
1295
+ },
1296
+
1297
+ className : {
1298
+ error : 'error',
1299
+ label : 'ui prompt label',
1300
+ pressed : 'down',
1301
+ success : 'success'
1302
+ },
1303
+
1304
+ error: {
1305
+ identifier : 'You must specify a string identifier for each field',
1306
+ method : 'The method you called is not defined.',
1307
+ noRule : 'There is no rule matching the one you specified',
1308
+ oldSyntax : 'Starting in 2.0 forms now only take a single settings object. Validation settings converted to new syntax automatically.'
1309
+ },
1310
+
1311
+ templates: {
1312
+
1313
+ // template that produces error message
1314
+ error: function(errors) {
1315
+ var
1316
+ html = '<ul class="list">'
1317
+ ;
1318
+ $.each(errors, function(index, value) {
1319
+ html += '<li>' + value + '</li>';
1320
+ });
1321
+ html += '</ul>';
1322
+ return $(html);
1323
+ },
1324
+
1325
+ // template that produces label
1326
+ prompt: function(errors) {
1327
+ return $('<div/>')
1328
+ .addClass('ui basic red pointing prompt label')
1329
+ .html(errors[0])
1330
+ ;
1331
+ }
1332
+ },
1333
+
1334
+ rules: {
1335
+
1336
+ // is not empty or blank string
1337
+ empty: function(value) {
1338
+ return !(value === undefined || '' === value || $.isArray(value) && value.length === 0);
1339
+ },
1340
+
1341
+ // checkbox checked
1342
+ checked: function() {
1343
+ return ($(this).filter(':checked').length > 0);
1344
+ },
1345
+
1346
+ // is most likely an email
1347
+ email: function(value){
1348
+ return $.fn.form.settings.regExp.email.test(value);
1349
+ },
1350
+
1351
+ // value is most likely url
1352
+ url: function(value) {
1353
+ return $.fn.form.settings.regExp.url.test(value);
1354
+ },
1355
+
1356
+ // matches specified regExp
1357
+ regExp: function(value, regExp) {
1358
+ if(regExp instanceof RegExp) {
1359
+ return value.match(regExp);
1360
+ }
1361
+ var
1362
+ regExpParts = regExp.match($.fn.form.settings.regExp.flags),
1363
+ flags
1364
+ ;
1365
+ // regular expression specified as /baz/gi (flags)
1366
+ if(regExpParts) {
1367
+ regExp = (regExpParts.length >= 2)
1368
+ ? regExpParts[1]
1369
+ : regExp
1370
+ ;
1371
+ flags = (regExpParts.length >= 3)
1372
+ ? regExpParts[2]
1373
+ : ''
1374
+ ;
1375
+ }
1376
+ return value.match( new RegExp(regExp, flags) );
1377
+ },
1378
+
1379
+ // is valid integer or matches range
1380
+ integer: function(value, range) {
1381
+ var
1382
+ intRegExp = $.fn.form.settings.regExp.integer,
1383
+ min,
1384
+ max,
1385
+ parts
1386
+ ;
1387
+ if( !range || ['', '..'].indexOf(range) !== -1) {
1388
+ // do nothing
1389
+ }
1390
+ else if(range.indexOf('..') == -1) {
1391
+ if(intRegExp.test(range)) {
1392
+ min = max = range - 0;
1393
+ }
1394
+ }
1395
+ else {
1396
+ parts = range.split('..', 2);
1397
+ if(intRegExp.test(parts[0])) {
1398
+ min = parts[0] - 0;
1399
+ }
1400
+ if(intRegExp.test(parts[1])) {
1401
+ max = parts[1] - 0;
1402
+ }
1403
+ }
1404
+ return (
1405
+ intRegExp.test(value) &&
1406
+ (min === undefined || value >= min) &&
1407
+ (max === undefined || value <= max)
1408
+ );
1409
+ },
1410
+
1411
+ // is valid number (with decimal)
1412
+ decimal: function(value) {
1413
+ return $.fn.form.settings.regExp.decimal.test(value);
1414
+ },
1415
+
1416
+ // is valid number
1417
+ number: function(value) {
1418
+ return $.fn.form.settings.regExp.number.test(value);
1419
+ },
1420
+
1421
+ // is value (case insensitive)
1422
+ is: function(value, text) {
1423
+ text = (typeof text == 'string')
1424
+ ? text.toLowerCase()
1425
+ : text
1426
+ ;
1427
+ value = (typeof value == 'string')
1428
+ ? value.toLowerCase()
1429
+ : value
1430
+ ;
1431
+ return (value == text);
1432
+ },
1433
+
1434
+ // is value
1435
+ isExactly: function(value, text) {
1436
+ return (value == text);
1437
+ },
1438
+
1439
+ // value is not another value (case insensitive)
1440
+ not: function(value, notValue) {
1441
+ value = (typeof value == 'string')
1442
+ ? value.toLowerCase()
1443
+ : value
1444
+ ;
1445
+ notValue = (typeof notValue == 'string')
1446
+ ? notValue.toLowerCase()
1447
+ : notValue
1448
+ ;
1449
+ return (value != notValue);
1450
+ },
1451
+
1452
+ // value is not another value (case sensitive)
1453
+ notExactly: function(value, notValue) {
1454
+ return (value != notValue);
1455
+ },
1456
+
1457
+ // value contains text (insensitive)
1458
+ contains: function(value, text) {
1459
+ // escape regex characters
1460
+ text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
1461
+ return (value.search( new RegExp(text, 'i') ) !== -1);
1462
+ },
1463
+
1464
+ // value contains text (case sensitive)
1465
+ containsExactly: function(value, text) {
1466
+ // escape regex characters
1467
+ text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
1468
+ return (value.search( new RegExp(text) ) !== -1);
1469
+ },
1470
+
1471
+ // value contains text (insensitive)
1472
+ doesntContain: function(value, text) {
1473
+ // escape regex characters
1474
+ text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
1475
+ return (value.search( new RegExp(text, 'i') ) === -1);
1476
+ },
1477
+
1478
+ // value contains text (case sensitive)
1479
+ doesntContainExactly: function(value, text) {
1480
+ // escape regex characters
1481
+ text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
1482
+ return (value.search( new RegExp(text) ) === -1);
1483
+ },
1484
+
1485
+ // is at least string length
1486
+ minLength: function(value, requiredLength) {
1487
+ return (value !== undefined)
1488
+ ? (value.length >= requiredLength)
1489
+ : false
1490
+ ;
1491
+ },
1492
+
1493
+ // see rls notes for 2.0.6 (this is a duplicate of minLength)
1494
+ length: function(value, requiredLength) {
1495
+ return (value !== undefined)
1496
+ ? (value.length >= requiredLength)
1497
+ : false
1498
+ ;
1499
+ },
1500
+
1501
+ // is exactly length
1502
+ exactLength: function(value, requiredLength) {
1503
+ return (value !== undefined)
1504
+ ? (value.length == requiredLength)
1505
+ : false
1506
+ ;
1507
+ },
1508
+
1509
+ // is less than length
1510
+ maxLength: function(value, maxLength) {
1511
+ return (value !== undefined)
1512
+ ? (value.length <= maxLength)
1513
+ : false
1514
+ ;
1515
+ },
1516
+
1517
+ // matches another field
1518
+ match: function(value, identifier) {
1519
+ var
1520
+ $form = $(this),
1521
+ matchingValue
1522
+ ;
1523
+ if( $('[data-validate="'+ identifier +'"]').length > 0 ) {
1524
+ matchingValue = $('[data-validate="'+ identifier +'"]').val();
1525
+ }
1526
+ else if($('#' + identifier).length > 0) {
1527
+ matchingValue = $('#' + identifier).val();
1528
+ }
1529
+ else if($('[name="' + identifier +'"]').length > 0) {
1530
+ matchingValue = $('[name="' + identifier + '"]').val();
1531
+ }
1532
+ else if( $('[name="' + identifier +'[]"]').length > 0 ) {
1533
+ matchingValue = $('[name="' + identifier +'[]"]');
1534
+ }
1535
+ return (matchingValue !== undefined)
1536
+ ? ( value.toString() == matchingValue.toString() )
1537
+ : false
1538
+ ;
1539
+ },
1540
+
1541
+ // different than another field
1542
+ different: function(value, identifier) {
1543
+ // use either id or name of field
1544
+ var
1545
+ $form = $(this),
1546
+ matchingValue
1547
+ ;
1548
+ if( $('[data-validate="'+ identifier +'"]').length > 0 ) {
1549
+ matchingValue = $('[data-validate="'+ identifier +'"]').val();
1550
+ }
1551
+ else if($('#' + identifier).length > 0) {
1552
+ matchingValue = $('#' + identifier).val();
1553
+ }
1554
+ else if($('[name="' + identifier +'"]').length > 0) {
1555
+ matchingValue = $('[name="' + identifier + '"]').val();
1556
+ }
1557
+ else if( $('[name="' + identifier +'[]"]').length > 0 ) {
1558
+ matchingValue = $('[name="' + identifier +'[]"]');
1559
+ }
1560
+ return (matchingValue !== undefined)
1561
+ ? ( value.toString() !== matchingValue.toString() )
1562
+ : false
1563
+ ;
1564
+ },
1565
+
1566
+ creditCard: function(cardNumber, cardTypes) {
1567
+ var
1568
+ cards = {
1569
+ visa: {
1570
+ pattern : /^4/,
1571
+ length : [16]
1572
+ },
1573
+ amex: {
1574
+ pattern : /^3[47]/,
1575
+ length : [15]
1576
+ },
1577
+ mastercard: {
1578
+ pattern : /^5[1-5]/,
1579
+ length : [16]
1580
+ },
1581
+ discover: {
1582
+ pattern : /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/,
1583
+ length : [16]
1584
+ },
1585
+ unionPay: {
1586
+ pattern : /^(62|88)/,
1587
+ length : [16, 17, 18, 19]
1588
+ },
1589
+ jcb: {
1590
+ pattern : /^35(2[89]|[3-8][0-9])/,
1591
+ length : [16]
1592
+ },
1593
+ maestro: {
1594
+ pattern : /^(5018|5020|5038|6304|6759|676[1-3])/,
1595
+ length : [12, 13, 14, 15, 16, 17, 18, 19]
1596
+ },
1597
+ dinersClub: {
1598
+ pattern : /^(30[0-5]|^36)/,
1599
+ length : [14]
1600
+ },
1601
+ laser: {
1602
+ pattern : /^(6304|670[69]|6771)/,
1603
+ length : [16, 17, 18, 19]
1604
+ },
1605
+ visaElectron: {
1606
+ pattern : /^(4026|417500|4508|4844|491(3|7))/,
1607
+ length : [16]
1608
+ }
1609
+ },
1610
+ valid = {},
1611
+ validCard = false,
1612
+ requiredTypes = (typeof cardTypes == 'string')
1613
+ ? cardTypes.split(',')
1614
+ : false,
1615
+ unionPay,
1616
+ validation
1617
+ ;
1618
+
1619
+ if(typeof cardNumber !== 'string' || cardNumber.length === 0) {
1620
+ return;
1621
+ }
1622
+
1623
+ // allow dashes in card
1624
+ cardNumber = cardNumber.replace(/[\-]/g, '');
1625
+
1626
+ // verify card types
1627
+ if(requiredTypes) {
1628
+ $.each(requiredTypes, function(index, type){
1629
+ // verify each card type
1630
+ validation = cards[type];
1631
+ if(validation) {
1632
+ valid = {
1633
+ length : ($.inArray(cardNumber.length, validation.length) !== -1),
1634
+ pattern : (cardNumber.search(validation.pattern) !== -1)
1635
+ };
1636
+ if(valid.length && valid.pattern) {
1637
+ validCard = true;
1638
+ }
1639
+ }
1640
+ });
1641
+
1642
+ if(!validCard) {
1643
+ return false;
1644
+ }
1645
+ }
1646
+
1647
+ // skip luhn for UnionPay
1648
+ unionPay = {
1649
+ number : ($.inArray(cardNumber.length, cards.unionPay.length) !== -1),
1650
+ pattern : (cardNumber.search(cards.unionPay.pattern) !== -1)
1651
+ };
1652
+ if(unionPay.number && unionPay.pattern) {
1653
+ return true;
1654
+ }
1655
+
1656
+ // verify luhn, adapted from <https://gist.github.com/2134376>
1657
+ var
1658
+ length = cardNumber.length,
1659
+ multiple = 0,
1660
+ producedValue = [
1661
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
1662
+ [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
1663
+ ],
1664
+ sum = 0
1665
+ ;
1666
+ while (length--) {
1667
+ sum += producedValue[multiple][parseInt(cardNumber.charAt(length), 10)];
1668
+ multiple ^= 1;
1669
+ }
1670
+ return (sum % 10 === 0 && sum > 0);
1671
+ },
1672
+
1673
+ minCount: function(value, minCount) {
1674
+ if(minCount == 0) {
1675
+ return true;
1676
+ }
1677
+ if(minCount == 1) {
1678
+ return (value !== '');
1679
+ }
1680
+ return (value.split(',').length >= minCount);
1681
+ },
1682
+
1683
+ exactCount: function(value, exactCount) {
1684
+ if(exactCount == 0) {
1685
+ return (value === '');
1686
+ }
1687
+ if(exactCount == 1) {
1688
+ return (value !== '' && value.search(',') === -1);
1689
+ }
1690
+ return (value.split(',').length == exactCount);
1691
+ },
1692
+
1693
+ maxCount: function(value, maxCount) {
1694
+ if(maxCount == 0) {
1695
+ return false;
1696
+ }
1697
+ if(maxCount == 1) {
1698
+ return (value.search(',') === -1);
1699
+ }
1700
+ return (value.split(',').length <= maxCount);
1701
+ }
1702
+ }
1703
+
1704
+ };
1705
+
1706
+ })( jQuery, window, document );