chemistrykit 3.8.1 → 3.9.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG.md +15 -5
  3. data/Gemfile +4 -0
  4. data/README.md +13 -1
  5. data/Rakefile +3 -3
  6. data/chemistrykit.gemspec +7 -3
  7. data/features/brew.feature +1 -1
  8. data/features/chemists.feature +56 -1
  9. data/features/concurrency.feature +2 -2
  10. data/features/exit_status.feature +1 -0
  11. data/features/logging.feature +88 -85
  12. data/features/reporting.feature +105 -0
  13. data/features/step_definitions/steps.rb +4 -4
  14. data/features/support/env.rb +1 -1
  15. data/features/tags.feature +1 -0
  16. data/lib/chemistrykit/chemist.rb +6 -1
  17. data/lib/chemistrykit/chemist/repository/csv_chemist_repository.rb +1 -1
  18. data/lib/chemistrykit/cli/cli.rb +33 -12
  19. data/lib/chemistrykit/configuration.rb +2 -2
  20. data/lib/chemistrykit/formula/formula_lab.rb +13 -0
  21. data/lib/chemistrykit/{parallel_tests_mods.rb → parallel_tests/rspec/runner.rb} +5 -5
  22. data/lib/chemistrykit/reporting/html_report_assembler.rb +170 -0
  23. data/lib/chemistrykit/rspec/html_formatter.rb +241 -0
  24. data/lib/chemistrykit/rspec/j_unit_formatter.rb +124 -0
  25. data/report/config.rb +28 -0
  26. data/report/index.html +213 -0
  27. data/report/javascripts/foundation/foundation.abide.js +194 -0
  28. data/report/javascripts/foundation/foundation.alerts.js +52 -0
  29. data/report/javascripts/foundation/foundation.clearing.js +516 -0
  30. data/report/javascripts/foundation/foundation.cookie.js +74 -0
  31. data/report/javascripts/foundation/foundation.dropdown.js +177 -0
  32. data/report/javascripts/foundation/foundation.forms.js +533 -0
  33. data/report/javascripts/foundation/foundation.interchange.js +280 -0
  34. data/report/javascripts/foundation/foundation.joyride.js +850 -0
  35. data/report/javascripts/foundation/foundation.js +440 -0
  36. data/report/javascripts/foundation/foundation.magellan.js +135 -0
  37. data/report/javascripts/foundation/foundation.orbit.js +412 -0
  38. data/report/javascripts/foundation/foundation.placeholder.js +179 -0
  39. data/report/javascripts/foundation/foundation.reveal.js +330 -0
  40. data/report/javascripts/foundation/foundation.section.js +400 -0
  41. data/report/javascripts/foundation/foundation.tooltips.js +208 -0
  42. data/report/javascripts/foundation/foundation.topbar.js +300 -0
  43. data/report/javascripts/vendor/custom.modernizr.js +4 -0
  44. data/report/javascripts/vendor/jquery.js +9789 -0
  45. data/report/sass/_normalize.scss +402 -0
  46. data/report/sass/_settings.scss +1301 -0
  47. data/report/sass/app.scss +571 -0
  48. data/report/stylesheets/app.css +3636 -0
  49. data/spec/integration/lib/chemistrykit/formula/formula_lab_spec.rb +26 -2
  50. data/spec/integration/lib/chemistrykit/reporting/html_reporting_assembler_spec.rb +18 -0
  51. data/spec/support/evidence/results_0.html +30 -0
  52. data/spec/support/evidence/results_1.html +27 -0
  53. data/spec/unit/lib/chemistrykit/chemist/repository/csv_chemist_repository_spec.rb +15 -2
  54. data/spec/unit/lib/chemistrykit/chemist_spec.rb +17 -1
  55. data/spec/unit/lib/chemistrykit/configuration_spec.rb +2 -2
  56. data/spec/unit/lib/chemistrykit/formula/formula_lab_spec.rb +7 -0
  57. data/spec/unit/lib/chemistrykit/reporting/html_reporting_assembler_spec.rb +22 -0
  58. metadata +94 -13
  59. data/lib/chemistrykit/j_unit.rb +0 -121
@@ -0,0 +1,124 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'time'
4
+ require 'builder'
5
+ require 'rspec/core/formatters/base_formatter'
6
+
7
+ # An RSpec formatter for generating results in JUnit format
8
+ # updated from https://github.com/natritmeyer/yarjuf
9
+ module ChemistryKit
10
+ module RSpec
11
+ class JUnitFormatter < ::RSpec::Core::Formatters::BaseFormatter
12
+
13
+ # rspec formatter methods we care about
14
+
15
+ def initialize(output)
16
+ super output
17
+ @test_suite_results = {}
18
+ @builder = Builder::XmlMarkup.new indent: 2
19
+ end
20
+
21
+ def example_passed(example)
22
+ add_to_test_suite_results example
23
+ end
24
+
25
+ def example_failed(example)
26
+ add_to_test_suite_results example
27
+ end
28
+
29
+ def example_pending(example)
30
+ add_to_test_suite_results example
31
+ end
32
+
33
+ def dump_summary(duration, example_count, failure_count, pending_count)
34
+ build_results duration, example_count, failure_count, pending_count
35
+ output.puts @builder.target!
36
+ end
37
+
38
+ protected
39
+
40
+ def add_to_test_suite_results(example)
41
+ suite_name = JUnitFormatter.root_group_name_for(example)
42
+ @test_suite_results[suite_name] = [] unless @test_suite_results.keys.include? suite_name
43
+ @test_suite_results[suite_name] << example
44
+ end
45
+
46
+ def failure_details_for(example)
47
+ exception = example.metadata[:execution_result][:exception]
48
+ exception.nil? ? '' : "#{exception.message}\n#{format_backtrace(exception.backtrace, example).join("\n")}"
49
+ end
50
+
51
+ # utility methods
52
+
53
+ def self.count_in_suite_of_type(suite, test_case_result_type)
54
+ suite.select { |example| example.metadata[:execution_result][:status] == test_case_result_type }.size
55
+ end
56
+
57
+ def self.root_group_name_for(example)
58
+ group_hierarchy = []
59
+ current_example_group = example.metadata[:example_group]
60
+ until current_example_group.nil?
61
+ group_hierarchy.unshift current_example_group
62
+ current_example_group = current_example_group[:example_group]
63
+ end
64
+ JUnitFormatter.slugify group_hierarchy.first[:description]
65
+ end
66
+
67
+ # methods to build the xml for test suites and individual tests
68
+
69
+ def build_results(duration, example_count, failure_count, pending_count)
70
+ @builder.instruct! :xml, version: '1.0', encoding: 'UTF-8'
71
+ @builder.testsuites errors: 0, failures: failure_count, skipped: pending_count, tests: example_count, time: duration, timestamp: Time.now.iso8601 do
72
+ build_all_suites
73
+ end
74
+ end
75
+
76
+ def build_all_suites
77
+ @test_suite_results.each do |suite_name, tests|
78
+ build_test_suite suite_name, tests
79
+ end
80
+ end
81
+
82
+ def build_test_suite(suite_name, tests)
83
+ failure_count = JUnitFormatter.count_in_suite_of_type tests, 'failed'
84
+ skipped_count = JUnitFormatter.count_in_suite_of_type tests, 'pending'
85
+
86
+ @builder.testsuite name: suite_name, tests: tests.size, errors: 0, failures: failure_count, skipped: skipped_count do
87
+ @builder.properties
88
+ build_all_tests tests
89
+ end
90
+ end
91
+
92
+ def build_all_tests(tests)
93
+ tests.each do |test|
94
+ build_test test
95
+ end
96
+ end
97
+
98
+ def build_test(test)
99
+ test_name = JUnitFormatter.slugify test.metadata[:full_description]
100
+ execution_time = test.metadata[:execution_result][:run_time]
101
+ test_status = test.metadata[:execution_result][:status]
102
+
103
+ @builder.testcase name: test_name, time: execution_time do
104
+ case test_status
105
+ when 'pending' then @builder.skipped
106
+ when 'failed' then build_failed_test test
107
+ end
108
+ end
109
+ end
110
+
111
+ def build_failed_test(test)
112
+ failure_message = "failed #{test.metadata[:full_description]}"
113
+
114
+ @builder.failure message: failure_message, type: 'failed' do
115
+ @builder.cdata! failure_details_for test
116
+ end
117
+ end
118
+
119
+ def self.slugify(string)
120
+ string.downcase.strip.gsub(' ', '_').gsub(/[^\w-]/, '')
121
+ end
122
+ end
123
+ end
124
+ end
data/report/config.rb ADDED
@@ -0,0 +1,28 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'zurb-foundation'
4
+ # Require any additional compass plugins here.
5
+
6
+ # Set this to the root of your project when deployed:
7
+ # rubocop:disable UnusedLocalVariable
8
+ http_path = '/'
9
+ css_dir = 'stylesheets'
10
+ sass_dir = 'sass'
11
+ images_dir = 'images'
12
+ javascripts_dir = 'javascripts'
13
+ # enable:disable UnusedLocalVariable
14
+
15
+ # You can select your preferred output style here (can be overridden via the command line):
16
+ # output_style = :expanded or :nested or :compact or :compressed
17
+
18
+ # To enable relative paths to assets via compass helper functions. Uncomment:
19
+ # relative_assets = true
20
+
21
+ # To disable debugging comments that display the original location of your selectors. Uncomment:
22
+ # line_comments = false
23
+
24
+ # If you prefer the indented syntax, you might want to regenerate this
25
+ # project again passing --syntax sass, or you can uncomment this:
26
+ # preferred_syntax = :sass
27
+ # and then run:
28
+ # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
data/report/index.html ADDED
@@ -0,0 +1,213 @@
1
+ <!DOCTYPE html>
2
+ <!--[if IE 8]> <html class="no-js lt-ie9" lang="en" > <![endif]-->
3
+ <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
4
+
5
+ <head>
6
+ <meta charset="utf-8">
7
+ <meta name="viewport" content="width=device-width">
8
+ <title>Foundation 4</title>
9
+
10
+
11
+ <link rel="stylesheet" href="stylesheets/app.css">
12
+ <link href="http://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css" rel="stylesheet">
13
+
14
+ <script src="javascripts/vendor/custom.modernizr.js"></script>
15
+
16
+ </head>
17
+ <body>
18
+
19
+ <header class="row">
20
+ <div class="large-12 columns">
21
+ <h2>ChemistryKit Brew Results</h2>
22
+ </div>
23
+ </header>
24
+
25
+ <div class="report">
26
+ <div class="summary">
27
+ <div class="row status failing">
28
+ <div class="large-12 columns">
29
+ <h1><i class="icon-ok-sign"></i> Brew Failing</h1>
30
+ </div>
31
+ </div>
32
+ <div class="row details">
33
+ <div class="large-12 columns">
34
+ <ul class="large-block-grid-5">
35
+ <li><i class="icon-beaker passing-color"></i><p>23 Beakers</p></li>
36
+ <li><i class="icon-tint reaction-color"></i><p>123 Reactions</p></li>
37
+ <li><i class="icon-warning-sign failing-color"></i><p>1 Failures</p></li>
38
+ <li><i class="icon-question-sign pending-color"></i><p>1 Pending</p></li>
39
+ <li><i class="icon-time"></i><p>125s Duration</p></li>
40
+ </ul>
41
+ </div>
42
+ </div>
43
+ </div>
44
+
45
+ <div class="results">
46
+ <div class="row example-group passing">
47
+ <div class="large-12 columns">
48
+ <h3><i class="icon-beaker"></i> This Part of the Site</h3>
49
+ <div class="examples">
50
+
51
+ <div class="row example passing">
52
+ <div class="large-12 columns">
53
+
54
+ <div class="row example-heading">
55
+
56
+ <div class="large-9 columns">
57
+ <p>Should do this and do that.</p>
58
+ </div>
59
+ <div class="large-3 columns text-right">
60
+ <p>0.00361s</p>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+
66
+ <div class="row example passing">
67
+ <div class="large-12 columns">
68
+
69
+ <div class="row example-heading">
70
+
71
+ <div class="large-9 columns">
72
+ <p>Should do this and do that.</p>
73
+ </div>
74
+ <div class="large-3 columns text-right">
75
+ <p>0.00361s</p>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+
81
+ <div class="row example pending">
82
+ <div class="large-12 columns">
83
+
84
+ <div class="row example-heading">
85
+ <div class="large-9 columns">
86
+ <p>Should do this and do that.</p>
87
+ </div>
88
+ <div class="large-3 columns text-right">
89
+ <p>0.00361s</p>
90
+ </div>
91
+ </div>
92
+
93
+ <div class="row example-body">
94
+ <div class="large-12 columns">
95
+ <div class="row exception">
96
+ <div class="large-12 columns">
97
+ <pre>PENDING: this is some message!</pre>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </div>
102
+
103
+
104
+
105
+
106
+ </div>
107
+ </div>
108
+
109
+ </div>
110
+ </div>
111
+ </div>
112
+
113
+ <div class="row example-group failing">
114
+ <div class="large-12 columns">
115
+ <h3><i class="icon-beaker"></i> This Part of the Site</h3>
116
+ <div class="examples">
117
+
118
+ <div class="row example failing">
119
+ <div class="large-12 columns">
120
+
121
+ <div class="row example-heading">
122
+ <div class="large-9 columns">
123
+ <p>Should do this and do that.</p>
124
+ </div>
125
+ <div class="large-3 columns text-right">
126
+ <p>0.00361s</p>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="row example-body">
131
+ <div class="large-12 columns">
132
+
133
+ <div class="row exception">
134
+ <div class="large-12 columns">
135
+ <pre>Failure/Error: @driver.title.should include("Yoogle") expected "Google" to include "Yoogle"</pre>
136
+ </div>
137
+ </div>
138
+
139
+ <div class="row code-snippet">
140
+ <div class="large-12 columns">
141
+
142
+ <pre class="ruby"><code><span class="linenum">2</span> <span class="ident">it</span> <span class="punct">&quot;</span><span class="string">loads an external web page, from 1, example 1</span><span class="punct">&quot;</span> <span class="keyword">do</span>
143
+ <span class="linenum">3</span> <span class="attribute">@driver</span><span class="punct">.</span><span class="ident">get</span> <span class="punct">&quot;</span><span class="string">http://www.google.com</span><span class="punct">&quot;</span>
144
+ <span class="offending"><span class="linenum">4</span> <span class="attribute">@driver</span><span class="punct">.</span><span class="ident">title</span><span class="punct">.</span><span class="ident">should</span> <span class="ident">include</span><span class="punct">(&quot;</span><span class="string">Yoogle</span><span class="punct">&quot;)</span></span>
145
+ <span class="linenum">5</span> <span class="keyword">end</span>
146
+ <span class="linenum">6</span> <span class="ident">it</span> <span class="punct">&quot;</span><span class="string">loads an external web page, from 1, example 2</span><span class="punct">&quot;</span> <span class="keyword">do</span></code></pre>
147
+
148
+
149
+ </div>
150
+ </div>
151
+
152
+ <div class="row extra-content">
153
+ <div class="large-12 columns">
154
+ <div class="section-container auto" data-section="">
155
+ <section>
156
+ <p class="title" data-section-title><a href="#panel1">Backtrace</a></p>
157
+ <div class="content" data-section-content>
158
+ <pre># ./beakers/first_beaker.rb:4:in `block (2 levels) in <top (required)>'
159
+ # /Users/jfox/development/arrgyle/chemistrykit/lib/chemistrykit/cli/cli.rb:199:in `block (2 levels) in rspec_config'
160
+ # /Users/jfox/development/arrgyle/chemistrykit/lib/chemistrykit/cli/cli.rb:242:in `run_rspec'
161
+ # /Users/jfox/development/arrgyle/chemistrykit/lib/chemistrykit/cli/cli.rb:114:in `brew'
162
+ </pre>
163
+ </div>
164
+ </section>
165
+ <section>
166
+ <p class="title" data-section-title><a href="#panel2">Section 2</a></p>
167
+ <div class="content" data-section-content>
168
+ <p>Content of section 2.</p>
169
+ </div>
170
+ </section>
171
+ </div>
172
+ </div>
173
+ </div>
174
+
175
+
176
+
177
+
178
+
179
+ </div>
180
+ </div>
181
+ </div>
182
+ </div>
183
+
184
+ <div class="row example passing">
185
+ <div class="large-12 columns">
186
+ <div class="row example-heading">
187
+ <div class="large-9 columns">
188
+ <p>Should do this and do that.</p>
189
+ </div>
190
+ <div class="large-3 columns text-right">
191
+ <p>0.00361s</p>
192
+ </div>
193
+ </div>
194
+ </div>
195
+ </div>
196
+
197
+ </div>
198
+ </div>
199
+
200
+ </div>
201
+
202
+ <script>
203
+ document.write('<script src=' +
204
+ ('__proto__' in {} ? 'javascripts/vendor/zepto' : 'javascripts/vendor/jquery') +
205
+ '.js><\/script>')
206
+ </script>
207
+ <script src="javascripts/foundation/foundation.js"></script>
208
+ <script src="javascripts/foundation/foundation.section.js"></script>
209
+ <script>
210
+ $(document).foundation();
211
+ </script>
212
+ </body>
213
+ </html>
@@ -0,0 +1,194 @@
1
+ /*jslint unparam: true, browser: true, indent: 2 */
2
+
3
+ ;(function ($, window, document, undefined) {
4
+ 'use strict';
5
+
6
+ Foundation.libs.abide = {
7
+ name : 'abide',
8
+
9
+ version : '4.3.0',
10
+
11
+ settings : {
12
+ live_validate : true,
13
+ focus_on_invalid : true,
14
+ timeout : 1000,
15
+ patterns : {
16
+ alpha: /[a-zA-Z]+/,
17
+ alpha_numeric : /[a-zA-Z0-9]+/,
18
+ integer: /-?\d+/,
19
+ number: /-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?/,
20
+
21
+ // generic password: upper-case, lower-case, number/special character, and min 8 characters
22
+ password : /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/,
23
+
24
+ // amex, visa, diners
25
+ card : /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/,
26
+ cvv : /^([0-9]){3,4}$/,
27
+
28
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address
29
+ email : /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
30
+
31
+ url: /(https?|ftp|file|ssh):\/\/(((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?/,
32
+ // abc.de
33
+ domain: /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/,
34
+
35
+ datetime: /([0-2][0-9]{3})\-([0-1][0-9])\-([0-3][0-9])T([0-5][0-9])\:([0-5][0-9])\:([0-5][0-9])(Z|([\-\+]([0-1][0-9])\:00))/,
36
+ // YYYY-MM-DD
37
+ date: /(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))/,
38
+ // HH:MM:SS
39
+ time : /(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}/,
40
+ dateISO: /\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/,
41
+ // MM/DD/YYYY
42
+ month_day_year : /(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/,
43
+
44
+ // #FFF or #FFFFFF
45
+ color: /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/
46
+ }
47
+ },
48
+
49
+ timer : null,
50
+
51
+ init : function (scope, method, options) {
52
+ if (typeof method === 'object') {
53
+ $.extend(true, this.settings, method);
54
+ }
55
+
56
+ if (typeof method !== 'string') {
57
+ if (!this.settings.init) { this.events(); }
58
+
59
+ } else {
60
+ return this[method].call(this, options);
61
+ }
62
+ },
63
+
64
+ events : function () {
65
+ var self = this,
66
+ forms = $('form[data-abide]', this.scope).attr('novalidate', 'novalidate');
67
+
68
+ forms
69
+ .on('submit validate', function (e) {
70
+ return self.validate($(this).find('input, textarea, select').get(), e);
71
+ });
72
+
73
+ this.settings.init = true;
74
+
75
+ if (!this.settings.live_validate) return;
76
+
77
+ forms
78
+ .find('input, textarea, select')
79
+ .on('blur change', function (e) {
80
+ self.validate([this], e);
81
+ })
82
+ .on('keydown', function (e) {
83
+ clearTimeout(self.timer);
84
+ self.timer = setTimeout(function () {
85
+ self.validate([this], e);
86
+ }.bind(this), self.settings.timeout);
87
+ });
88
+ },
89
+
90
+ validate : function (els, e) {
91
+ var validations = this.parse_patterns(els),
92
+ validation_count = validations.length,
93
+ form = $(els[0]).closest('form');
94
+
95
+ while (validation_count--) {
96
+ if (!validations[validation_count] && /submit/.test(e.type)) {
97
+ if (this.settings.focus_on_invalid) els[validation_count].focus();
98
+ form.trigger('invalid');
99
+ $(els[validation_count]).closest('form').attr('data-invalid', '');
100
+ return false;
101
+ }
102
+ }
103
+
104
+ if (/submit/.test(e.type)) {
105
+ form.trigger('valid');
106
+ }
107
+
108
+ form.removeAttr('data-invalid');
109
+
110
+ return true;
111
+ },
112
+
113
+ parse_patterns : function (els) {
114
+ var count = els.length,
115
+ el_patterns = [];
116
+
117
+ for (var i = count - 1; i >= 0; i--) {
118
+ el_patterns.push(this.pattern(els[i]));
119
+ }
120
+
121
+ return this.check_validation_and_apply_styles(el_patterns);
122
+ },
123
+
124
+ pattern : function (el) {
125
+ var type = el.getAttribute('type'),
126
+ required = typeof el.getAttribute('required') === 'string';
127
+
128
+ if (this.settings.patterns.hasOwnProperty(type)) {
129
+ return [el, this.settings.patterns[type], required];
130
+ }
131
+
132
+ var pattern = el.getAttribute('pattern') || '';
133
+
134
+ if (this.settings.patterns.hasOwnProperty(pattern) && pattern.length > 0) {
135
+ return [el, this.settings.patterns[pattern], required];
136
+ } else if (pattern.length > 0) {
137
+ return [el, new RegExp(pattern), required];
138
+ }
139
+
140
+ pattern = /.*/;
141
+
142
+ return [el, pattern, required];
143
+ },
144
+
145
+ check_validation_and_apply_styles : function (el_patterns) {
146
+ var count = el_patterns.length,
147
+ validations = [];
148
+
149
+ for (var i = count - 1; i >= 0; i--) {
150
+ var el = el_patterns[i][0],
151
+ required = el_patterns[i][2],
152
+ value = el.value,
153
+ is_radio = el.type === "radio",
154
+ valid_length = (required) ? (el.value.length > 0) : true;
155
+
156
+ if (is_radio && required) {
157
+ validations.push(this.valid_radio(el, required));
158
+ } else {
159
+ if (el_patterns[i][1].test(value) && valid_length ||
160
+ !required && el.value.length < 1) {
161
+ $(el).removeAttr('data-invalid').parent().removeClass('error');
162
+ validations.push(true);
163
+ } else {
164
+ $(el).attr('data-invalid', '').parent().addClass('error');
165
+ validations.push(false);
166
+ }
167
+ }
168
+ }
169
+
170
+ return validations;
171
+ },
172
+
173
+ valid_radio : function (el, required) {
174
+ var name = el.getAttribute('name'),
175
+ group = document.getElementsByName(name),
176
+ count = group.length,
177
+ valid = false;
178
+
179
+ for (var i=0; i < count; i++) {
180
+ if (group[i].checked) valid = true;
181
+ }
182
+
183
+ for (var i=0; i < count; i++) {
184
+ if (valid) {
185
+ $(group[i]).removeAttr('data-invalid').parent().removeClass('error');
186
+ } else {
187
+ $(group[i]).attr('data-invalid', '').parent().addClass('error');
188
+ }
189
+ }
190
+
191
+ return valid;
192
+ }
193
+ };
194
+ }(Foundation.zj, this, this.document));