caring_form 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.travis.yml +17 -0
  4. data/Appraisals +18 -0
  5. data/Gemfile +9 -0
  6. data/Guardfile +15 -0
  7. data/LICENSE +22 -0
  8. data/README.md +33 -0
  9. data/Rakefile +12 -0
  10. data/app/assets/javascripts/caring_form/form-observer.coffee +63 -0
  11. data/app/assets/javascripts/caring_form/main.coffee +15 -0
  12. data/app/assets/javascripts/caring_form/remote-validator.coffee +71 -0
  13. data/app/assets/javascripts/caring_form/rule-based-validator.coffee +37 -0
  14. data/app/assets/javascripts/caring_form/setup.coffee +5 -0
  15. data/app/assets/javascripts/caring_form/webshims-customization.coffee +25 -0
  16. data/app/assets/javascripts/caring_forms.js +7 -0
  17. data/caring_form.gemspec +31 -0
  18. data/gemfiles/rails_3_1.gemfile +8 -0
  19. data/gemfiles/rails_3_2.gemfile +8 -0
  20. data/gemfiles/rails_4.gemfile +7 -0
  21. data/gemfiles/rails_4_1.gemfile +8 -0
  22. data/lib/caring_form.rb +20 -0
  23. data/lib/caring_form/action_view_extensions/builder.rb +75 -0
  24. data/lib/caring_form/action_view_extensions/config.rb +4 -0
  25. data/lib/caring_form/action_view_extensions/flash_error_helper.rb +28 -0
  26. data/lib/caring_form/action_view_extensions/form_helper.rb +33 -0
  27. data/lib/caring_form/active_model/monkey_patching.rb +32 -0
  28. data/lib/caring_form/dsl.rb +91 -0
  29. data/lib/caring_form/engine.rb +4 -0
  30. data/lib/caring_form/field/base.rb +145 -0
  31. data/lib/caring_form/field/check_box.rb +23 -0
  32. data/lib/caring_form/field/check_boxes.rb +15 -0
  33. data/lib/caring_form/field/collection.rb +48 -0
  34. data/lib/caring_form/field/dummy.rb +30 -0
  35. data/lib/caring_form/field/email.rb +41 -0
  36. data/lib/caring_form/field/full_name.rb +40 -0
  37. data/lib/caring_form/field/looking_for.rb +37 -0
  38. data/lib/caring_form/field/metadata.rb +26 -0
  39. data/lib/caring_form/field/radio_buttons.rb +15 -0
  40. data/lib/caring_form/field/string.rb +13 -0
  41. data/lib/caring_form/field/submit.rb +83 -0
  42. data/lib/caring_form/field/tel.rb +37 -0
  43. data/lib/caring_form/field/text.rb +13 -0
  44. data/lib/caring_form/field/us_zip_code.rb +37 -0
  45. data/lib/caring_form/field_container.rb +126 -0
  46. data/lib/caring_form/form_builder.rb +51 -0
  47. data/lib/caring_form/model.rb +58 -0
  48. data/lib/caring_form/model/active_model.rb +11 -0
  49. data/lib/caring_form/model/active_record.rb +38 -0
  50. data/lib/caring_form/simple_form/initializer.rb +26 -0
  51. data/lib/caring_form/simple_form/monkey_patching.rb +51 -0
  52. data/lib/caring_form/tools/referee.rb +62 -0
  53. data/lib/caring_form/version.rb +3 -0
  54. data/lib/tasks/webshims.rake +7 -0
  55. data/spec/caring_form/action_view_extensions/flash_error_helper_spec.rb +50 -0
  56. data/spec/caring_form/action_view_extensions/form_helper_spec.rb +72 -0
  57. data/spec/caring_form/dsl_spec.rb +21 -0
  58. data/spec/caring_form/field/base_spec.rb +204 -0
  59. data/spec/caring_form/field/check_boxes_spec.rb +32 -0
  60. data/spec/caring_form/field/collection_spec.rb +28 -0
  61. data/spec/caring_form/field/radio_buttons_spec.rb +29 -0
  62. data/spec/caring_form/field/submit_spec.rb +57 -0
  63. data/spec/caring_form/field_container_spec.rb +85 -0
  64. data/spec/caring_form/form_builder_spec.rb +113 -0
  65. data/spec/caring_form/model_spec.rb +235 -0
  66. data/spec/caring_form/tools/referee_spec.rb +86 -0
  67. data/spec/spec_helper.rb +28 -0
  68. data/spec/support/nokogiri_matcher.rb +204 -0
  69. metadata +278 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9189ecabe4fbff2003c4100405b4b46bd96d222f
4
+ data.tar.gz: 811c47c4ed64c413dfc232642c23be924910bb58
5
+ SHA512:
6
+ metadata.gz: 51315c24df9c1872cf23ccc67799709a12597713b81982537c0e67678830d56dd62f0c5263e62d2b5ac5aea9ecd93a5c7a2f267adbf24a1702d9e93fa949e30c
7
+ data.tar.gz: db02f2691ea49e9cd8821c01397d813e4b62bd572c5254ca54118ab876cea5319466af9717c2667f40e4200d4b9c94c392f81ce6829696eca74ebbf8dd02ee7f
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ gemfiles/*.gemfile.lock
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ bin
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ cache: bundler
3
+ script: bundle exec rake spec
4
+
5
+ gemfile:
6
+ - gemfiles/rails_3_1.gemfile
7
+ - gemfiles/rails_3_2.gemfile
8
+ - gemfiles/rails_4.gemfile
9
+ - gemfiles/rails_4_1.gemfile
10
+
11
+ rvm:
12
+ - 1.9.3
13
+ - 2.1.0
14
+
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
@@ -0,0 +1,18 @@
1
+ appraise "rails-3-1" do
2
+ gem "minitest", '~> 4.0'
3
+ gem "rails", "~>3.1.0"
4
+ end
5
+
6
+ appraise "rails-3-2" do
7
+ gem "minitest", '~> 4.0'
8
+ gem "rails", "~>3.2.14"
9
+ end
10
+
11
+ appraise "rails-4" do
12
+ gem "rails", "~>4.0.0"
13
+ end
14
+
15
+ appraise "rails-4-1" do
16
+ gem "rails", "~> 4.1.1"
17
+ gem "simple_form", '~> 3.1.0.rc1'
18
+ end
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :development do
4
+ gem 'guard-coffeescript'
5
+ gem 'guard-jammit'
6
+ gem 'guard-minitest'
7
+ end
8
+
9
+ gemspec
@@ -0,0 +1,15 @@
1
+ # More info at https://github.com/guard/guard#readme
2
+
3
+ guard 'coffeescript', :input => 'javascripts/src', :output => 'javascripts/compiled', :all_on_start => true
4
+
5
+ guard :jammit, :config_path => 'javascripts/assets.yml', :output_folder => 'javascripts' do
6
+ watch(%r{^javascripts/compiled/(.*)\.js$})
7
+ watch('javascripts/assets.yml')
8
+ end
9
+
10
+ guard 'minitest' do
11
+ # with Minitest::Spec
12
+ watch(%r|^spec/(.*)_spec\.rb|)
13
+ watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
14
+ watch(%r|^spec/spec_helper\.rb|) { "spec" }
15
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Mathieu Lajugie
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,33 @@
1
+ # CaringForm
2
+
3
+ [![Build Status](https://magnum.travis-ci.com/caring/caring_form.png?token=sKHYu3Tc8rtipypNpjWg&branch=master)](https://magnum.travis-ci.com/caring/caring_form)
4
+
5
+ Standardized forms, styles and JS validation for caring.com
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'caring_form'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+ $ rake webshims:update_public # Allows dynamic module loading to continue working.
17
+
18
+
19
+ ## Usage
20
+
21
+ In `app/assets/javascripts/application.js` or any other asset pipeline enabled JS.
22
+
23
+ ```
24
+ //= require caring_forms
25
+ ```
26
+
27
+ ## Contributing
28
+
29
+ 1. Fork it
30
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
31
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
32
+ 4. Push to the branch (`git push origin my-new-feature`)
33
+ 5. Create new Pull Request
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rake/testtask'
4
+ require 'bundler/gem_tasks'
5
+ require 'appraisal'
6
+
7
+ Rake::TestTask.new('spec') do |task|
8
+ task.pattern = 'spec/**/*_spec.rb'
9
+ end
10
+
11
+ desc 'Default: run unit tests.'
12
+ task :default => :spec
@@ -0,0 +1,63 @@
1
+ $ = jQuery
2
+
3
+ class CARING.FormObserver
4
+
5
+ @enableButtons: (form) ->
6
+ form
7
+ .find('.primary-button, .secondary-button, .marketing-button')
8
+ .prop('disabled', false)
9
+ .removeClass('disabled')
10
+
11
+ @disableButtons: (form) ->
12
+ # disable buttons in the next click as IE7-8 won't submit the form
13
+ # if the submit button is disabled while in the callback flow...
14
+ setTimeout((->
15
+ form
16
+ .find('.primary-button, .secondary-button, .marketing-button')
17
+ .prop('disabled', true)
18
+ .addClass('disabled')
19
+ ), 0)
20
+ true
21
+
22
+ constructor: (@selector) ->
23
+
24
+ start: ->
25
+ changedProxy = $.proxy(@valueChanged, this)
26
+ $(@selector).on
27
+ 'input': changedProxy
28
+ 'change': changedProxy
29
+ 'invalid': (event) =>
30
+ @markAsSubmitted(event.currentTarget)
31
+ @showErrorOn(event.target)
32
+ 'submit': (event) =>
33
+ # IE7-8 trigger a form submit even if the form is not valid...
34
+ if $(event.currentTarget).checkValidity()
35
+ form = $(event.currentTarget)
36
+ @constructor.disableButtons(form) unless form.hasClass('no-disable-buttons')
37
+
38
+ wasSubmitted: (form) ->
39
+ $(form).hasClass('submitted')
40
+
41
+ markAsSubmitted: (form) ->
42
+ $(form).addClass('submitted')
43
+
44
+ fieldContainerFor: (element) ->
45
+ $(element).closest('.field')
46
+
47
+ showErrorOn: (element) ->
48
+ @fieldContainerFor(element).addClass('field-with-errors')
49
+
50
+ hideErrorOn: (element) ->
51
+ @fieldContainerFor(element).removeClass('field-with-errors')
52
+
53
+ hideErrorIfValidOnNextClick: (element) ->
54
+ # element validity is not accurate when checked right away, so let's
55
+ # wait for the next click in the event loop
56
+ setTimeout((=>
57
+ if $(element).hasClass('indicator-field-ok') or $(element).checkValidity()
58
+ @hideErrorOn(element)
59
+ ), 0)
60
+
61
+ valueChanged: (event) ->
62
+ return unless @wasSubmitted(event.currentTarget)
63
+ @hideErrorIfValidOnNextClick(event.target)
@@ -0,0 +1,15 @@
1
+ jQuery ($) ->
2
+ observer = new CARING.FormObserver('form.caring-form')
3
+ observer.start()
4
+
5
+ validators = [
6
+ new CARING.RemoteValidator('.validate-remotely')
7
+ new CARING.RuleBasedValidator()
8
+ ]
9
+ validator.addBehavior() for validator in validators
10
+
11
+ # allow to close flash
12
+ $('.flash .flash-close > a').click (event) ->
13
+ event.preventDefault()
14
+ flash = $(event.target).closest('.flash')
15
+ flash.slideUp()
@@ -0,0 +1,71 @@
1
+ $ = jQuery
2
+
3
+ class CARING.RemoteValidator
4
+
5
+ _removeAllValidationClassesFor = (element) ->
6
+ $(element).removeClass('indicator-field-ok indicator-field-ban indicator-field-loading')
7
+
8
+ _refreshFormValidationFor = (element) -> $(element).trigger('input', [true])
9
+
10
+ _setErrorMessage = (field, message) ->
11
+ if field.setCustomValidity?
12
+ $(field).setCustomValidity(message)
13
+
14
+ _showInlineError = (field, message) ->
15
+ field = $(field)
16
+ error = field.next('.inline-error')
17
+ error.text(message).show()
18
+ offset = field.offset()
19
+ offset.top += field.outerHeight()
20
+ if window.navigator.userAgent.match(/Gecko/)
21
+ offset.top += 1
22
+ offset.left += 2
23
+ offset.left += field.outerWidth() - error.outerWidth() - 2
24
+ error.offset(offset)
25
+
26
+ _hideInlineError = (field) ->
27
+ $(field).next('.inline-error')
28
+ .hide()
29
+ .text('')
30
+
31
+ constructor: (@fieldSelector, options = {}) ->
32
+ @validate($(@fieldSelector)) if $(@fieldSelector).hasClass("auto-validate")
33
+
34
+ addBehavior: ->
35
+ $(@fieldSelector).on 'keyup', =>
36
+ field = $(@fieldSelector)
37
+ _setErrorMessage(field, field.data('init-message') or "Please wait while I check ...")
38
+ clearTimeout(buffering) if buffering = field.data('buffering')
39
+ buffering = setTimeout((=>
40
+ @validate(field)
41
+ field.data(buffering: null)
42
+ ), parseInt(field.data('max-idle-time') || "300", 10))
43
+ field.data(buffering: buffering)
44
+
45
+ validate: (element) ->
46
+ _removeAllValidationClassesFor(element)
47
+ value = element.val()
48
+ if value is ''
49
+ _setErrorMessage(element, '')
50
+ _refreshFormValidationFor(element)
51
+ _hideInlineError(element)
52
+ else
53
+ element.addClass('indicator-field-loading')
54
+ $.getJSON(element.data('validator-url'), {value: value}, (data, status, xhr) ->
55
+ _removeAllValidationClassesFor(element)
56
+ if data.valid
57
+ element
58
+ .addClass('indicator-field-ok')
59
+ .each (index, element) ->
60
+ $(element).trigger('data-valid')
61
+ _setErrorMessage(element, '')
62
+ _refreshFormValidationFor(element)
63
+ _hideInlineError(element)
64
+ else
65
+ element
66
+ .addClass('indicator-field-ban')
67
+ .each (index, element) ->
68
+ _setErrorMessage(element, data.message || data.short_message)
69
+ _refreshFormValidationFor(element)
70
+ _showInlineError(element, data.short_message)
71
+ )
@@ -0,0 +1,37 @@
1
+ $ = jQuery
2
+
3
+ class CARING.RuleBasedValidator
4
+
5
+ # RULES: hash of {name: rule}
6
+ # where rule has a targetEvent and an action
7
+ #
8
+ # The rule based validator expects rules set to DOM elements
9
+ # as data attributes. The data attribute is the name of the rule
10
+ # and its value is the target selector.
11
+
12
+ RULES =
13
+ 'optional-if-absent':
14
+ targetEvent: 'change'
15
+ action: (source, target) ->
16
+ sourceRequired = $(target).val() isnt ''
17
+ $(source).attr('required', sourceRequired)
18
+
19
+ 'optional-if-present':
20
+ targetEvent: 'change'
21
+ action: (source, target) ->
22
+ sourceRequired = $(target).val() is ''
23
+ $(source).attr('required', sourceRequired)
24
+
25
+ _applyRule = (source, ruleName, rule) ->
26
+ targetSelector = $(source).data(ruleName)
27
+ # run the rule once for each (source, target) and each
28
+ # time a target triggers the rule targetEvent
29
+ $(targetSelector)
30
+ .each(-> rule.action(source, this))
31
+ .bind(rule.targetEvent, (event) ->
32
+ rule.action(source, event.target)
33
+ )
34
+
35
+ addBehavior: ->
36
+ for name, rule of RULES
37
+ $("*[data-#{name}]").each -> _applyRule(this, name, rule)
@@ -0,0 +1,5 @@
1
+ window.CARING ||= {}
2
+ jQuery.webshims.setOptions('basePath', '/webshims/shims/')
3
+ jQuery.webshims.polyfill('forms forms-ext');
4
+ jQuery(document).ready () ->
5
+ CARING.WebshimsCustomization.normalizeFormValidation();
@@ -0,0 +1,25 @@
1
+ $ = jQuery
2
+
3
+ useWebshimsFormUI = ->
4
+ $.webshims.setOptions('forms',
5
+ replaceValidationUI: true
6
+ customMessages: true
7
+ overrideMessages: true
8
+ )
9
+
10
+ if messages = $.webshims.validityMessages['en']
11
+ messages.valueMissing.defaultMessage = "Please fill out this field. {%title}"
12
+ messages.valueMissing.select = "Please select an option. {%title}"
13
+ messages.valueMissing.radio = "Please select one of these options. {%title}"
14
+ messages.patternMismatch = "Please match the requested format. {%title}"
15
+
16
+ useWebshimsDateSlider = ->
17
+ $.webshims.setOptions('forms-ext',
18
+ datepicker:
19
+ dateFormat: 'm/d/y'
20
+ )
21
+
22
+ CARING.WebshimsCustomization =
23
+ normalizeFormValidation: ->
24
+ useWebshimsFormUI()
25
+ useWebshimsDateSlider()
@@ -0,0 +1,7 @@
1
+ //= require webshims/polyfiller
2
+ //= require caring_form/setup
3
+ //= require caring_form/form-observer
4
+ //= require caring_form/remote-validator
5
+ //= require caring_form/rule-based-validator
6
+ //= require caring_form/webshims-customization
7
+ //= require caring_form/main
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/caring_form/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Mathieu Lajugie"]
6
+ gem.email = ['mathieu@caring.com']
7
+ gem.description = %q{Build clean, robust and consistent forms for Caring.com.}
8
+ gem.summary = gem.description
9
+ gem.homepage = 'http://www.caring.com'
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "caring_form"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = CaringForm::VERSION
17
+ gem.platform = Gem::Platform::RUBY
18
+
19
+ gem.add_dependency 'simple_form'
20
+ gem.add_dependency 'actionpack'
21
+ gem.add_dependency 'activemodel'
22
+ gem.add_dependency 'webshims-rails', '~> 1.15.6'
23
+
24
+ gem.add_development_dependency "appraisal", '~> 0.5.2'
25
+ gem.add_development_dependency 'rake'
26
+ gem.add_development_dependency 'minitest'
27
+ gem.add_development_dependency 'minitest-reporters'
28
+ gem.add_development_dependency 'nokogiri'
29
+ gem.add_development_dependency 'awesome_print'
30
+ gem.add_development_dependency 'pry-nav'
31
+ end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "minitest", "~> 4.0"
6
+ gem "rails", "~>3.1.0"
7
+
8
+ gemspec :path=>"../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "minitest", "~> 4.0"
6
+ gem "rails", "~>3.2.14"
7
+
8
+ gemspec :path=>"../"