fomantic-ui-sass 2.6.4

Sign up to get free protection for your applications and to get access to all the features.
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 );