fomantic-ui-sass 2.6.4

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 (165) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +5 -0
  5. data/CHANGELOG.md +370 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +177 -0
  9. data/Rakefile +8 -0
  10. data/app/assets/fonts/semantic-ui/brand-icons.eot +0 -0
  11. data/app/assets/fonts/semantic-ui/brand-icons.svg +1008 -0
  12. data/app/assets/fonts/semantic-ui/brand-icons.ttf +0 -0
  13. data/app/assets/fonts/semantic-ui/brand-icons.woff +0 -0
  14. data/app/assets/fonts/semantic-ui/brand-icons.woff2 +0 -0
  15. data/app/assets/fonts/semantic-ui/icons.eot +0 -0
  16. data/app/assets/fonts/semantic-ui/icons.otf +0 -0
  17. data/app/assets/fonts/semantic-ui/icons.svg +1518 -0
  18. data/app/assets/fonts/semantic-ui/icons.ttf +0 -0
  19. data/app/assets/fonts/semantic-ui/icons.woff +0 -0
  20. data/app/assets/fonts/semantic-ui/icons.woff2 +0 -0
  21. data/app/assets/fonts/semantic-ui/outline-icons.eot +0 -0
  22. data/app/assets/fonts/semantic-ui/outline-icons.svg +366 -0
  23. data/app/assets/fonts/semantic-ui/outline-icons.ttf +0 -0
  24. data/app/assets/fonts/semantic-ui/outline-icons.woff +0 -0
  25. data/app/assets/fonts/semantic-ui/outline-icons.woff2 +0 -0
  26. data/app/assets/images/semantic-ui/flags.png +0 -0
  27. data/app/assets/javascripts/semantic-ui.js +27 -0
  28. data/app/assets/javascripts/semantic-ui/accordion.js +613 -0
  29. data/app/assets/javascripts/semantic-ui/api.js +1167 -0
  30. data/app/assets/javascripts/semantic-ui/calendar.js +1476 -0
  31. data/app/assets/javascripts/semantic-ui/checkbox.js +828 -0
  32. data/app/assets/javascripts/semantic-ui/colorize.js +280 -0
  33. data/app/assets/javascripts/semantic-ui/dimmer.js +735 -0
  34. data/app/assets/javascripts/semantic-ui/dropdown.js +4030 -0
  35. data/app/assets/javascripts/semantic-ui/embed.js +706 -0
  36. data/app/assets/javascripts/semantic-ui/form.js +1707 -0
  37. data/app/assets/javascripts/semantic-ui/modal.js +1090 -0
  38. data/app/assets/javascripts/semantic-ui/nag.js +507 -0
  39. data/app/assets/javascripts/semantic-ui/popup.js +1532 -0
  40. data/app/assets/javascripts/semantic-ui/progress.js +923 -0
  41. data/app/assets/javascripts/semantic-ui/range.js +278 -0
  42. data/app/assets/javascripts/semantic-ui/rating.js +511 -0
  43. data/app/assets/javascripts/semantic-ui/search.js +1515 -0
  44. data/app/assets/javascripts/semantic-ui/shape.js +921 -0
  45. data/app/assets/javascripts/semantic-ui/sidebar.js +1033 -0
  46. data/app/assets/javascripts/semantic-ui/site.js +490 -0
  47. data/app/assets/javascripts/semantic-ui/state.js +708 -0
  48. data/app/assets/javascripts/semantic-ui/sticky.js +959 -0
  49. data/app/assets/javascripts/semantic-ui/tab.js +952 -0
  50. data/app/assets/javascripts/semantic-ui/toast.js +592 -0
  51. data/app/assets/javascripts/semantic-ui/transition.js +1106 -0
  52. data/app/assets/javascripts/semantic-ui/video.js +532 -0
  53. data/app/assets/javascripts/semantic-ui/visibility.js +1311 -0
  54. data/app/assets/javascripts/semantic-ui/visit.js +525 -0
  55. data/app/assets/stylesheets/semantic-ui.scss +5 -0
  56. data/app/assets/stylesheets/semantic-ui/collections/_all.scss +6 -0
  57. data/app/assets/stylesheets/semantic-ui/collections/_breadcrumb.scss +124 -0
  58. data/app/assets/stylesheets/semantic-ui/collections/_form.scss +1158 -0
  59. data/app/assets/stylesheets/semantic-ui/collections/_grid.scss +2093 -0
  60. data/app/assets/stylesheets/semantic-ui/collections/_menu.scss +2193 -0
  61. data/app/assets/stylesheets/semantic-ui/collections/_message.scss +606 -0
  62. data/app/assets/stylesheets/semantic-ui/collections/_table.scss +1117 -0
  63. data/app/assets/stylesheets/semantic-ui/elements/_all.scss +16 -0
  64. data/app/assets/stylesheets/semantic-ui/elements/_button.scss +4530 -0
  65. data/app/assets/stylesheets/semantic-ui/elements/_container.scss +145 -0
  66. data/app/assets/stylesheets/semantic-ui/elements/_divider.scss +259 -0
  67. data/app/assets/stylesheets/semantic-ui/elements/_flag.scss +1036 -0
  68. data/app/assets/stylesheets/semantic-ui/elements/_header.scss +762 -0
  69. data/app/assets/stylesheets/semantic-ui/elements/_icon.scss +6330 -0
  70. data/app/assets/stylesheets/semantic-ui/elements/_image.scss +310 -0
  71. data/app/assets/stylesheets/semantic-ui/elements/_input.scss +519 -0
  72. data/app/assets/stylesheets/semantic-ui/elements/_label.scss +1395 -0
  73. data/app/assets/stylesheets/semantic-ui/elements/_list.scss +959 -0
  74. data/app/assets/stylesheets/semantic-ui/elements/_loader.scss +458 -0
  75. data/app/assets/stylesheets/semantic-ui/elements/_placeholder.scss +242 -0
  76. data/app/assets/stylesheets/semantic-ui/elements/_rail.scss +152 -0
  77. data/app/assets/stylesheets/semantic-ui/elements/_reveal.scss +295 -0
  78. data/app/assets/stylesheets/semantic-ui/elements/_segment.scss +884 -0
  79. data/app/assets/stylesheets/semantic-ui/elements/_step.scss +675 -0
  80. data/app/assets/stylesheets/semantic-ui/globals/_all.scss +3 -0
  81. data/app/assets/stylesheets/semantic-ui/globals/_reset.scss +485 -0
  82. data/app/assets/stylesheets/semantic-ui/globals/_site.scss +206 -0
  83. data/app/assets/stylesheets/semantic-ui/globals/_variables.scss +4 -0
  84. data/app/assets/stylesheets/semantic-ui/modules/_accordion.scss +247 -0
  85. data/app/assets/stylesheets/semantic-ui/modules/_all.scss +20 -0
  86. data/app/assets/stylesheets/semantic-ui/modules/_calendar.scss +165 -0
  87. data/app/assets/stylesheets/semantic-ui/modules/_checkbox.scss +718 -0
  88. data/app/assets/stylesheets/semantic-ui/modules/_dimmer.scss +464 -0
  89. data/app/assets/stylesheets/semantic-ui/modules/_dropdown.scss +1745 -0
  90. data/app/assets/stylesheets/semantic-ui/modules/_embed.scss +165 -0
  91. data/app/assets/stylesheets/semantic-ui/modules/_modal.scss +646 -0
  92. data/app/assets/stylesheets/semantic-ui/modules/_nag.scss +148 -0
  93. data/app/assets/stylesheets/semantic-ui/modules/_popup.scss +789 -0
  94. data/app/assets/stylesheets/semantic-ui/modules/_progress.scss +523 -0
  95. data/app/assets/stylesheets/semantic-ui/modules/_range.scss +192 -0
  96. data/app/assets/stylesheets/semantic-ui/modules/_rating.scss +263 -0
  97. data/app/assets/stylesheets/semantic-ui/modules/_search.scss +445 -0
  98. data/app/assets/stylesheets/semantic-ui/modules/_shape.scss +154 -0
  99. data/app/assets/stylesheets/semantic-ui/modules/_sidebar.scss +626 -0
  100. data/app/assets/stylesheets/semantic-ui/modules/_sticky.scss +78 -0
  101. data/app/assets/stylesheets/semantic-ui/modules/_tab.scss +92 -0
  102. data/app/assets/stylesheets/semantic-ui/modules/_toast.scss +291 -0
  103. data/app/assets/stylesheets/semantic-ui/modules/_transition.scss +2059 -0
  104. data/app/assets/stylesheets/semantic-ui/modules/_video.scss +125 -0
  105. data/app/assets/stylesheets/semantic-ui/views/_ad.scss +275 -0
  106. data/app/assets/stylesheets/semantic-ui/views/_all.scss +6 -0
  107. data/app/assets/stylesheets/semantic-ui/views/_card.scss +1124 -0
  108. data/app/assets/stylesheets/semantic-ui/views/_comment.scss +296 -0
  109. data/app/assets/stylesheets/semantic-ui/views/_feed.scss +314 -0
  110. data/app/assets/stylesheets/semantic-ui/views/_item.scss +555 -0
  111. data/app/assets/stylesheets/semantic-ui/views/_statistic.scss +583 -0
  112. data/app/helpers/semantic_breadcrumbs_helper.rb +10 -0
  113. data/app/helpers/semantic_flash_helper.rb +22 -0
  114. data/app/helpers/semantic_icon_helper.rb +8 -0
  115. data/app/views/semantic/_breadcrumbs.html.erb +12 -0
  116. data/fomantic-ui-sass.gemspec +31 -0
  117. data/lib/fomantic-ui-sass.rb +62 -0
  118. data/lib/fomantic/ui/sass/breadcrumbs.rb +41 -0
  119. data/lib/fomantic/ui/sass/engine.rb +23 -0
  120. data/lib/fomantic/ui/sass/version.rb +8 -0
  121. data/spec/dummy/README.rdoc +28 -0
  122. data/spec/dummy/Rakefile +6 -0
  123. data/spec/dummy/app/assets/images/.keep +0 -0
  124. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  125. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  126. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  127. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  128. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  129. data/spec/dummy/app/mailers/.keep +0 -0
  130. data/spec/dummy/app/models/.keep +0 -0
  131. data/spec/dummy/app/models/concerns/.keep +0 -0
  132. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  133. data/spec/dummy/bin/bundle +3 -0
  134. data/spec/dummy/bin/rails +4 -0
  135. data/spec/dummy/bin/rake +4 -0
  136. data/spec/dummy/config.ru +4 -0
  137. data/spec/dummy/config/application.rb +28 -0
  138. data/spec/dummy/config/boot.rb +5 -0
  139. data/spec/dummy/config/environment.rb +5 -0
  140. data/spec/dummy/config/environments/development.rb +29 -0
  141. data/spec/dummy/config/environments/production.rb +80 -0
  142. data/spec/dummy/config/environments/test.rb +36 -0
  143. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  144. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  145. data/spec/dummy/config/initializers/inflections.rb +16 -0
  146. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  147. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  148. data/spec/dummy/config/initializers/session_store.rb +3 -0
  149. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  150. data/spec/dummy/config/locales/en.yml +23 -0
  151. data/spec/dummy/config/routes.rb +2 -0
  152. data/spec/dummy/lib/assets/.keep +0 -0
  153. data/spec/dummy/log/.keep +0 -0
  154. data/spec/dummy/public/404.html +58 -0
  155. data/spec/dummy/public/422.html +58 -0
  156. data/spec/dummy/public/500.html +57 -0
  157. data/spec/dummy/public/favicon.ico +0 -0
  158. data/spec/helpers/semantic_breadcrumbs_helper_spec.rb +38 -0
  159. data/spec/helpers/semantic_flash_helper_spec.rb +36 -0
  160. data/spec/helpers/semantic_icon_helper_spec.rb +48 -0
  161. data/spec/spec_helper.rb +17 -0
  162. data/tasks/converter.rb +216 -0
  163. data/templates/project/manifest.rb +29 -0
  164. data/templates/project/styles.scss +1 -0
  165. metadata +390 -0
@@ -0,0 +1,1707 @@
1
+ /*!
2
+ * # Semantic UI - 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
+ : (settings.shouldTrim) ? $.trim(value + '') : String(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
+ shouldTrim : true,
1223
+
1224
+ transition : 'scale',
1225
+ duration : 200,
1226
+
1227
+ onValid : function() {},
1228
+ onInvalid : function() {},
1229
+ onSuccess : function() { return true; },
1230
+ onFailure : function() { return false; },
1231
+
1232
+ metadata : {
1233
+ defaultValue : 'default',
1234
+ validate : 'validate'
1235
+ },
1236
+
1237
+ regExp: {
1238
+ htmlID : /^[a-zA-Z][\w:.-]*$/g,
1239
+ bracket : /\[(.*)\]/i,
1240
+ decimal : /^\d+\.?\d*$/,
1241
+ email : /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i,
1242
+ escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
1243
+ flags : /^\/(.*)\/(.*)?/,
1244
+ integer : /^\-?\d+$/,
1245
+ number : /^\-?\d*(\.\d+)?$/,
1246
+ url : /(https?:\/\/(?:www\.|(?!www))[^\s\.]+\.[^\s]{2,}|www\.[^\s]+\.[^\s]{2,})/i
1247
+ },
1248
+
1249
+ text: {
1250
+ unspecifiedRule : 'Please enter a valid value',
1251
+ unspecifiedField : 'This field'
1252
+ },
1253
+
1254
+ prompt: {
1255
+ empty : '{name} must have a value',
1256
+ checked : '{name} must be checked',
1257
+ email : '{name} must be a valid e-mail',
1258
+ url : '{name} must be a valid url',
1259
+ regExp : '{name} is not formatted correctly',
1260
+ integer : '{name} must be an integer',
1261
+ decimal : '{name} must be a decimal number',
1262
+ number : '{name} must be set to a number',
1263
+ is : '{name} must be "{ruleValue}"',
1264
+ isExactly : '{name} must be exactly "{ruleValue}"',
1265
+ not : '{name} cannot be set to "{ruleValue}"',
1266
+ notExactly : '{name} cannot be set to exactly "{ruleValue}"',
1267
+ contain : '{name} must contain "{ruleValue}"',
1268
+ containExactly : '{name} must contain exactly "{ruleValue}"',
1269
+ doesntContain : '{name} cannot contain "{ruleValue}"',
1270
+ doesntContainExactly : '{name} cannot contain exactly "{ruleValue}"',
1271
+ minLength : '{name} must be at least {ruleValue} characters',
1272
+ length : '{name} must be at least {ruleValue} characters',
1273
+ exactLength : '{name} must be exactly {ruleValue} characters',
1274
+ maxLength : '{name} cannot be longer than {ruleValue} characters',
1275
+ match : '{name} must match {ruleValue} field',
1276
+ different : '{name} must have a different value than {ruleValue} field',
1277
+ creditCard : '{name} must be a valid credit card number',
1278
+ minCount : '{name} must have at least {ruleValue} choices',
1279
+ exactCount : '{name} must have exactly {ruleValue} choices',
1280
+ maxCount : '{name} must have {ruleValue} or less choices'
1281
+ },
1282
+
1283
+ selector : {
1284
+ checkbox : 'input[type="checkbox"], input[type="radio"]',
1285
+ clear : '.clear',
1286
+ field : 'input, textarea, select',
1287
+ group : '.field',
1288
+ input : 'input',
1289
+ message : '.error.message',
1290
+ prompt : '.prompt.label',
1291
+ radio : 'input[type="radio"]',
1292
+ reset : '.reset:not([type="reset"])',
1293
+ submit : '.submit:not([type="submit"])',
1294
+ uiCheckbox : '.ui.checkbox',
1295
+ uiDropdown : '.ui.dropdown'
1296
+ },
1297
+
1298
+ className : {
1299
+ error : 'error',
1300
+ label : 'ui prompt label',
1301
+ pressed : 'down',
1302
+ success : 'success'
1303
+ },
1304
+
1305
+ error: {
1306
+ identifier : 'You must specify a string identifier for each field',
1307
+ method : 'The method you called is not defined.',
1308
+ noRule : 'There is no rule matching the one you specified',
1309
+ oldSyntax : 'Starting in 2.0 forms now only take a single settings object. Validation settings converted to new syntax automatically.'
1310
+ },
1311
+
1312
+ templates: {
1313
+
1314
+ // template that produces error message
1315
+ error: function(errors) {
1316
+ var
1317
+ html = '<ul class="list">'
1318
+ ;
1319
+ $.each(errors, function(index, value) {
1320
+ html += '<li>' + value + '</li>';
1321
+ });
1322
+ html += '</ul>';
1323
+ return $(html);
1324
+ },
1325
+
1326
+ // template that produces label
1327
+ prompt: function(errors) {
1328
+ return $('<div/>')
1329
+ .addClass('ui basic red pointing prompt label')
1330
+ .html(errors[0])
1331
+ ;
1332
+ }
1333
+ },
1334
+
1335
+ rules: {
1336
+
1337
+ // is not empty or blank string
1338
+ empty: function(value) {
1339
+ return !(value === undefined || '' === value || $.isArray(value) && value.length === 0);
1340
+ },
1341
+
1342
+ // checkbox checked
1343
+ checked: function() {
1344
+ return ($(this).filter(':checked').length > 0);
1345
+ },
1346
+
1347
+ // is most likely an email
1348
+ email: function(value){
1349
+ return $.fn.form.settings.regExp.email.test(value);
1350
+ },
1351
+
1352
+ // value is most likely url
1353
+ url: function(value) {
1354
+ return $.fn.form.settings.regExp.url.test(value);
1355
+ },
1356
+
1357
+ // matches specified regExp
1358
+ regExp: function(value, regExp) {
1359
+ if(regExp instanceof RegExp) {
1360
+ return value.match(regExp);
1361
+ }
1362
+ var
1363
+ regExpParts = regExp.match($.fn.form.settings.regExp.flags),
1364
+ flags
1365
+ ;
1366
+ // regular expression specified as /baz/gi (flags)
1367
+ if(regExpParts) {
1368
+ regExp = (regExpParts.length >= 2)
1369
+ ? regExpParts[1]
1370
+ : regExp
1371
+ ;
1372
+ flags = (regExpParts.length >= 3)
1373
+ ? regExpParts[2]
1374
+ : ''
1375
+ ;
1376
+ }
1377
+ return value.match( new RegExp(regExp, flags) );
1378
+ },
1379
+
1380
+ // is valid integer or matches range
1381
+ integer: function(value, range) {
1382
+ var
1383
+ intRegExp = $.fn.form.settings.regExp.integer,
1384
+ min,
1385
+ max,
1386
+ parts
1387
+ ;
1388
+ if( !range || ['', '..'].indexOf(range) !== -1) {
1389
+ // do nothing
1390
+ }
1391
+ else if(range.indexOf('..') == -1) {
1392
+ if(intRegExp.test(range)) {
1393
+ min = max = range - 0;
1394
+ }
1395
+ }
1396
+ else {
1397
+ parts = range.split('..', 2);
1398
+ if(intRegExp.test(parts[0])) {
1399
+ min = parts[0] - 0;
1400
+ }
1401
+ if(intRegExp.test(parts[1])) {
1402
+ max = parts[1] - 0;
1403
+ }
1404
+ }
1405
+ return (
1406
+ intRegExp.test(value) &&
1407
+ (min === undefined || value >= min) &&
1408
+ (max === undefined || value <= max)
1409
+ );
1410
+ },
1411
+
1412
+ // is valid number (with decimal)
1413
+ decimal: function(value) {
1414
+ return $.fn.form.settings.regExp.decimal.test(value);
1415
+ },
1416
+
1417
+ // is valid number
1418
+ number: function(value) {
1419
+ return $.fn.form.settings.regExp.number.test(value);
1420
+ },
1421
+
1422
+ // is value (case insensitive)
1423
+ is: function(value, text) {
1424
+ text = (typeof text == 'string')
1425
+ ? text.toLowerCase()
1426
+ : text
1427
+ ;
1428
+ value = (typeof value == 'string')
1429
+ ? value.toLowerCase()
1430
+ : value
1431
+ ;
1432
+ return (value == text);
1433
+ },
1434
+
1435
+ // is value
1436
+ isExactly: function(value, text) {
1437
+ return (value == text);
1438
+ },
1439
+
1440
+ // value is not another value (case insensitive)
1441
+ not: function(value, notValue) {
1442
+ value = (typeof value == 'string')
1443
+ ? value.toLowerCase()
1444
+ : value
1445
+ ;
1446
+ notValue = (typeof notValue == 'string')
1447
+ ? notValue.toLowerCase()
1448
+ : notValue
1449
+ ;
1450
+ return (value != notValue);
1451
+ },
1452
+
1453
+ // value is not another value (case sensitive)
1454
+ notExactly: function(value, notValue) {
1455
+ return (value != notValue);
1456
+ },
1457
+
1458
+ // value contains text (insensitive)
1459
+ contains: function(value, text) {
1460
+ // escape regex characters
1461
+ text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
1462
+ return (value.search( new RegExp(text, 'i') ) !== -1);
1463
+ },
1464
+
1465
+ // value contains text (case sensitive)
1466
+ containsExactly: function(value, text) {
1467
+ // escape regex characters
1468
+ text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
1469
+ return (value.search( new RegExp(text) ) !== -1);
1470
+ },
1471
+
1472
+ // value contains text (insensitive)
1473
+ doesntContain: function(value, text) {
1474
+ // escape regex characters
1475
+ text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
1476
+ return (value.search( new RegExp(text, 'i') ) === -1);
1477
+ },
1478
+
1479
+ // value contains text (case sensitive)
1480
+ doesntContainExactly: function(value, text) {
1481
+ // escape regex characters
1482
+ text = text.replace($.fn.form.settings.regExp.escape, "\\$&");
1483
+ return (value.search( new RegExp(text) ) === -1);
1484
+ },
1485
+
1486
+ // is at least string length
1487
+ minLength: function(value, requiredLength) {
1488
+ return (value !== undefined)
1489
+ ? (value.length >= requiredLength)
1490
+ : false
1491
+ ;
1492
+ },
1493
+
1494
+ // see rls notes for 2.0.6 (this is a duplicate of minLength)
1495
+ length: function(value, requiredLength) {
1496
+ return (value !== undefined)
1497
+ ? (value.length >= requiredLength)
1498
+ : false
1499
+ ;
1500
+ },
1501
+
1502
+ // is exactly length
1503
+ exactLength: function(value, requiredLength) {
1504
+ return (value !== undefined)
1505
+ ? (value.length == requiredLength)
1506
+ : false
1507
+ ;
1508
+ },
1509
+
1510
+ // is less than length
1511
+ maxLength: function(value, maxLength) {
1512
+ return (value !== undefined)
1513
+ ? (value.length <= maxLength)
1514
+ : false
1515
+ ;
1516
+ },
1517
+
1518
+ // matches another field
1519
+ match: function(value, identifier) {
1520
+ var
1521
+ $form = $(this),
1522
+ matchingValue
1523
+ ;
1524
+ if( $('[data-validate="'+ identifier +'"]').length > 0 ) {
1525
+ matchingValue = $('[data-validate="'+ identifier +'"]').val();
1526
+ }
1527
+ else if($('#' + identifier).length > 0) {
1528
+ matchingValue = $('#' + identifier).val();
1529
+ }
1530
+ else if($('[name="' + identifier +'"]').length > 0) {
1531
+ matchingValue = $('[name="' + identifier + '"]').val();
1532
+ }
1533
+ else if( $('[name="' + identifier +'[]"]').length > 0 ) {
1534
+ matchingValue = $('[name="' + identifier +'[]"]');
1535
+ }
1536
+ return (matchingValue !== undefined)
1537
+ ? ( value.toString() == matchingValue.toString() )
1538
+ : false
1539
+ ;
1540
+ },
1541
+
1542
+ // different than another field
1543
+ different: function(value, identifier) {
1544
+ // use either id or name of field
1545
+ var
1546
+ $form = $(this),
1547
+ matchingValue
1548
+ ;
1549
+ if( $('[data-validate="'+ identifier +'"]').length > 0 ) {
1550
+ matchingValue = $('[data-validate="'+ identifier +'"]').val();
1551
+ }
1552
+ else if($('#' + identifier).length > 0) {
1553
+ matchingValue = $('#' + identifier).val();
1554
+ }
1555
+ else if($('[name="' + identifier +'"]').length > 0) {
1556
+ matchingValue = $('[name="' + identifier + '"]').val();
1557
+ }
1558
+ else if( $('[name="' + identifier +'[]"]').length > 0 ) {
1559
+ matchingValue = $('[name="' + identifier +'[]"]');
1560
+ }
1561
+ return (matchingValue !== undefined)
1562
+ ? ( value.toString() !== matchingValue.toString() )
1563
+ : false
1564
+ ;
1565
+ },
1566
+
1567
+ creditCard: function(cardNumber, cardTypes) {
1568
+ var
1569
+ cards = {
1570
+ visa: {
1571
+ pattern : /^4/,
1572
+ length : [16]
1573
+ },
1574
+ amex: {
1575
+ pattern : /^3[47]/,
1576
+ length : [15]
1577
+ },
1578
+ mastercard: {
1579
+ pattern : /^5[1-5]/,
1580
+ length : [16]
1581
+ },
1582
+ discover: {
1583
+ 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)/,
1584
+ length : [16]
1585
+ },
1586
+ unionPay: {
1587
+ pattern : /^(62|88)/,
1588
+ length : [16, 17, 18, 19]
1589
+ },
1590
+ jcb: {
1591
+ pattern : /^35(2[89]|[3-8][0-9])/,
1592
+ length : [16]
1593
+ },
1594
+ maestro: {
1595
+ pattern : /^(5018|5020|5038|6304|6759|676[1-3])/,
1596
+ length : [12, 13, 14, 15, 16, 17, 18, 19]
1597
+ },
1598
+ dinersClub: {
1599
+ pattern : /^(30[0-5]|^36)/,
1600
+ length : [14]
1601
+ },
1602
+ laser: {
1603
+ pattern : /^(6304|670[69]|6771)/,
1604
+ length : [16, 17, 18, 19]
1605
+ },
1606
+ visaElectron: {
1607
+ pattern : /^(4026|417500|4508|4844|491(3|7))/,
1608
+ length : [16]
1609
+ }
1610
+ },
1611
+ valid = {},
1612
+ validCard = false,
1613
+ requiredTypes = (typeof cardTypes == 'string')
1614
+ ? cardTypes.split(',')
1615
+ : false,
1616
+ unionPay,
1617
+ validation
1618
+ ;
1619
+
1620
+ if(typeof cardNumber !== 'string' || cardNumber.length === 0) {
1621
+ return;
1622
+ }
1623
+
1624
+ // allow dashes in card
1625
+ cardNumber = cardNumber.replace(/[\-]/g, '');
1626
+
1627
+ // verify card types
1628
+ if(requiredTypes) {
1629
+ $.each(requiredTypes, function(index, type){
1630
+ // verify each card type
1631
+ validation = cards[type];
1632
+ if(validation) {
1633
+ valid = {
1634
+ length : ($.inArray(cardNumber.length, validation.length) !== -1),
1635
+ pattern : (cardNumber.search(validation.pattern) !== -1)
1636
+ };
1637
+ if(valid.length && valid.pattern) {
1638
+ validCard = true;
1639
+ }
1640
+ }
1641
+ });
1642
+
1643
+ if(!validCard) {
1644
+ return false;
1645
+ }
1646
+ }
1647
+
1648
+ // skip luhn for UnionPay
1649
+ unionPay = {
1650
+ number : ($.inArray(cardNumber.length, cards.unionPay.length) !== -1),
1651
+ pattern : (cardNumber.search(cards.unionPay.pattern) !== -1)
1652
+ };
1653
+ if(unionPay.number && unionPay.pattern) {
1654
+ return true;
1655
+ }
1656
+
1657
+ // verify luhn, adapted from <https://gist.github.com/2134376>
1658
+ var
1659
+ length = cardNumber.length,
1660
+ multiple = 0,
1661
+ producedValue = [
1662
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
1663
+ [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
1664
+ ],
1665
+ sum = 0
1666
+ ;
1667
+ while (length--) {
1668
+ sum += producedValue[multiple][parseInt(cardNumber.charAt(length), 10)];
1669
+ multiple ^= 1;
1670
+ }
1671
+ return (sum % 10 === 0 && sum > 0);
1672
+ },
1673
+
1674
+ minCount: function(value, minCount) {
1675
+ if(minCount == 0) {
1676
+ return true;
1677
+ }
1678
+ if(minCount == 1) {
1679
+ return (value !== '');
1680
+ }
1681
+ return (value.split(',').length >= minCount);
1682
+ },
1683
+
1684
+ exactCount: function(value, exactCount) {
1685
+ if(exactCount == 0) {
1686
+ return (value === '');
1687
+ }
1688
+ if(exactCount == 1) {
1689
+ return (value !== '' && value.search(',') === -1);
1690
+ }
1691
+ return (value.split(',').length == exactCount);
1692
+ },
1693
+
1694
+ maxCount: function(value, maxCount) {
1695
+ if(maxCount == 0) {
1696
+ return false;
1697
+ }
1698
+ if(maxCount == 1) {
1699
+ return (value.search(',') === -1);
1700
+ }
1701
+ return (value.split(',').length <= maxCount);
1702
+ }
1703
+ }
1704
+
1705
+ };
1706
+
1707
+ })( jQuery, window, document );