rails-angulate 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +32 -0
- data/Rakefile +2 -0
- data/lib/rails-angulate.rb +2 -0
- data/lib/rails/angulate.rb +21 -0
- data/lib/rails/angulate/configuration.rb +34 -0
- data/lib/rails/angulate/engine.rb +12 -0
- data/lib/rails/angulate/helpers.rb +12 -0
- data/lib/rails/angulate/helpers/form_builder.rb +35 -0
- data/lib/rails/angulate/helpers/form_helper.rb +73 -0
- data/lib/rails/angulate/helpers/tags.rb +16 -0
- data/lib/rails/angulate/helpers/tags/ng_email_field.rb +10 -0
- data/lib/rails/angulate/helpers/tags/ng_text_field.rb +53 -0
- data/lib/rails/angulate/helpers/tags/ng_validation_errors.rb +75 -0
- data/lib/rails/angulate/helpers/tags/tag_common.rb +33 -0
- data/lib/rails/angulate/mappers.rb +39 -0
- data/lib/rails/angulate/mappers/base.rb +77 -0
- data/lib/rails/angulate/mappers/format_validator_mapper.rb +34 -0
- data/lib/rails/angulate/mappers/length_validator_mapper.rb +47 -0
- data/lib/rails/angulate/mappers/numericality_validator_mapper.rb +84 -0
- data/lib/rails/angulate/mappers/validator_mapper.rb +15 -0
- data/lib/rails/angulate/railtie.rb +15 -0
- data/lib/rails/angulate/version.rb +5 -0
- metadata +111 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: b2c4edfa704869f0f851c31ed0a1d6664d91f159
|
|
4
|
+
data.tar.gz: d5bbc86ee369bf6716646f3bcd490a8065313f9c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 05f74b84bdd08df8df880bc56c48261d1b9ead1df116851a54670878bf69c2a1327383b3fe6ffa89bb0e20cedb40e7e5c420f797d6bf5313df31a4fe63078639
|
|
7
|
+
data.tar.gz: 0ad0bdc1418c1f63e58f156fb82d54e7fd256df9df93920d9bf9d8544f59760e69fa147be81fb46d30bd444bf0e89ffc7fdf7d83dba4cf88ab0dca94c7bd7f68
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 Stan Bondi
|
|
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.
|
data/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Rails::Angulate
|
|
2
|
+
|
|
3
|
+
Angulate adds AngularJS client-side field and validation helpers to Rails form helpers.
|
|
4
|
+
|
|
5
|
+
Under active development (started 25 June 2014) - will update readme once this is in a decent state.
|
|
6
|
+
i.e DON'T use this yet!
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
Add this line to your application's Gemfile:
|
|
11
|
+
|
|
12
|
+
gem 'rails-angulate'
|
|
13
|
+
|
|
14
|
+
And then execute:
|
|
15
|
+
|
|
16
|
+
$ bundle
|
|
17
|
+
|
|
18
|
+
Or install it yourself as:
|
|
19
|
+
|
|
20
|
+
$ gem install rails-angulate
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
TODO: Write usage instructions here
|
|
25
|
+
|
|
26
|
+
## Contributing
|
|
27
|
+
|
|
28
|
+
1. Fork it ( https://github.com/[my-github-username]/rails-angulate/fork )
|
|
29
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
30
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
31
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
32
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'rails'
|
|
2
|
+
require 'active_support'
|
|
3
|
+
|
|
4
|
+
require 'rails/angulate/version'
|
|
5
|
+
require 'rails/angulate/configuration'
|
|
6
|
+
require 'rails/angulate/helpers'
|
|
7
|
+
require 'rails/angulate/mappers'
|
|
8
|
+
require 'rails/angulate/engine'
|
|
9
|
+
|
|
10
|
+
module Rails
|
|
11
|
+
module Angulate
|
|
12
|
+
def self.configuration
|
|
13
|
+
@configuration ||= Configuration.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.configure
|
|
17
|
+
yield configuration
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
class Configuration
|
|
4
|
+
attr_writer :validator_mappings
|
|
5
|
+
##
|
|
6
|
+
# Set on what conditions do you want the validation messages to show
|
|
7
|
+
#
|
|
8
|
+
# Possible values:
|
|
9
|
+
# blur: only once the field has been visited
|
|
10
|
+
# dirty: only if the field is dirty
|
|
11
|
+
# submit_attempt: only once the user has submitted the form
|
|
12
|
+
attr_accessor :validate_on
|
|
13
|
+
|
|
14
|
+
attr_accessor :validate_show_condition
|
|
15
|
+
|
|
16
|
+
def initialize
|
|
17
|
+
self.validate_on = { submit_attempt: :or, blur: nil }
|
|
18
|
+
self.validate_show_condition = "%{field}.$invalid && (%{validate_on})"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validator_mappings
|
|
22
|
+
@validator_mappings ||= {
|
|
23
|
+
presence: 'required',
|
|
24
|
+
format: 'pattern',
|
|
25
|
+
length: 'maxlength'
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def add_mapper(name, mapper_class)
|
|
30
|
+
Rails::Angulate::Mappers.register_mapper(name, mapper_class)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
class Engine < ::Rails::Engine
|
|
4
|
+
initializer 'angulate.initialize' do
|
|
5
|
+
ActiveSupport.on_load(:action_view) do |base|
|
|
6
|
+
base.send(:include, ::Rails::Angulate::Helpers)
|
|
7
|
+
cattr_accessor(:default_form_builder) { ::Rails::Angulate::Helpers::FormBuilder }
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
module Helpers
|
|
4
|
+
class FormBuilder < ::ActionView::Helpers::FormBuilder
|
|
5
|
+
# Add prefixed field helpers
|
|
6
|
+
class_attribute :ng_field_helpers
|
|
7
|
+
self.ng_field_helpers = self.field_helpers.map { |f| "ng_#{f}".to_sym }
|
|
8
|
+
|
|
9
|
+
%i{
|
|
10
|
+
ng_text_field
|
|
11
|
+
ng_email_field
|
|
12
|
+
ng_error_messages_for
|
|
13
|
+
}.each do |_adv_method|
|
|
14
|
+
define_method _adv_method do |*args, &block|
|
|
15
|
+
options = args.extract_options!
|
|
16
|
+
options = objectify_options(options)
|
|
17
|
+
@template.send(_adv_method, @object_name, *args, options, &block)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
%i{
|
|
22
|
+
ng_form_name
|
|
23
|
+
ng_valid
|
|
24
|
+
ng_valid_for
|
|
25
|
+
ng_invalid_for
|
|
26
|
+
ng_invalid
|
|
27
|
+
}.each do |_simple_method|
|
|
28
|
+
define_method _simple_method do |*args, &block|
|
|
29
|
+
@template.send(_simple_method, object, *args, &block)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'rails/angulate/helpers/tags'
|
|
2
|
+
|
|
3
|
+
module Rails
|
|
4
|
+
module Angulate
|
|
5
|
+
module Helpers
|
|
6
|
+
module FormHelper
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
def ng_form_for(record, options = {}, &block)
|
|
10
|
+
options[:html] ||= {}
|
|
11
|
+
options[:html][:name] ||= options[:as] || ng_form_name(record)
|
|
12
|
+
form_for(record, options, &block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def ng_text_field(object_name, method, options = {})
|
|
16
|
+
Tags::NgTextField.new(object_name, method, self, options).render
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def ng_email_field(object_name, method, options = {})
|
|
20
|
+
Tags::NgEmailField.new(object_name, method, self, options).render
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def ng_error_messages_for(object_name, method, options = {})
|
|
24
|
+
Tags::NgValidationErrors.new(object_name, method, self, options).render
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def ng_valid(record, &block)
|
|
28
|
+
valid_wrapper(record, '$valid', &block)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def ng_invalid(record, &block)
|
|
32
|
+
valid_wrapper(record, '$invalid', &block)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def ng_valid_for(record, attribute, &block)
|
|
36
|
+
valid_wrapper(record, '$valid', attribute, &block)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def ng_invalid_for(record, attribute, &block)
|
|
40
|
+
valid_wrapper(record, '$invalid', attribute, &block)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def ng_form_field_name(record, attribute)
|
|
44
|
+
"#{ng_form_name(record)}['#{object_name_for(record)}[#{attribute}]']"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def ng_form_name(record)
|
|
48
|
+
"#{object_name_for(record)}_form"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def object_name_for(record)
|
|
54
|
+
case record
|
|
55
|
+
when String, Symbol
|
|
56
|
+
record
|
|
57
|
+
else
|
|
58
|
+
object = record.is_a?(Array) ? record.last : record
|
|
59
|
+
raise ArgumentError, "First argument in form cannot contain nil or be empty" unless object
|
|
60
|
+
model_name_from_record_or_class(object).param_key
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def valid_wrapper(record, type, attribute = nil, &block)
|
|
65
|
+
ng_if = attribute.nil? ? ng_form_name(record) : ng_form_field_name(record, attribute)
|
|
66
|
+
content = capture(&block)
|
|
67
|
+
content_tag :span, content.html_safe, 'ng-if' => "#{ng_if}.#{type}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
module Helpers
|
|
4
|
+
module Tags
|
|
5
|
+
extend ActiveSupport::Autoload
|
|
6
|
+
|
|
7
|
+
eager_autoload do
|
|
8
|
+
autoload :TagCommon
|
|
9
|
+
autoload :NgTextField
|
|
10
|
+
autoload :NgEmailField
|
|
11
|
+
autoload :NgValidationErrors
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
module Helpers
|
|
4
|
+
module Tags
|
|
5
|
+
class NgTextField < ActionView::Helpers::Tags::TextField
|
|
6
|
+
include TagCommon
|
|
7
|
+
|
|
8
|
+
def render
|
|
9
|
+
options = @options.stringify_keys
|
|
10
|
+
options["size"] = options["maxlength"] unless options.key?("size")
|
|
11
|
+
options["type"] ||= field_type
|
|
12
|
+
options["value"] = options.fetch("value") { value_before_type_cast(object) } unless field_type == "file"
|
|
13
|
+
options["value"] &&= ERB::Util.html_escape(options["value"])
|
|
14
|
+
|
|
15
|
+
add_default_name_and_id(options)
|
|
16
|
+
set_ng_options(options)
|
|
17
|
+
add_ng_validation_attrs(options)
|
|
18
|
+
|
|
19
|
+
tag 'input', options
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def set_ng_options(options)
|
|
23
|
+
if options.has_key?("ng")
|
|
24
|
+
options.delete("ng").each do |k, v|
|
|
25
|
+
options["ng-#{k}"] = v
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
unless options.has_key?("ng-model")
|
|
30
|
+
options["ng-model"] = options.fetch("ngModel") do
|
|
31
|
+
ng_model_name(options["id"])
|
|
32
|
+
end.to_s
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def add_ng_validation_attrs(attrs)
|
|
37
|
+
validators.each do |validator|
|
|
38
|
+
attrs.reverse_merge!(validator_mapper_for(validator).ng_attributes)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def ng_model_name(id)
|
|
43
|
+
id.camelize(:lower)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.field_type
|
|
47
|
+
@field_type ||= super.sub(/^ng/, '')
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
module Helpers
|
|
4
|
+
module Tags
|
|
5
|
+
class NgValidationErrors < ActionView::Helpers::Tags::Base
|
|
6
|
+
include TagCommon
|
|
7
|
+
|
|
8
|
+
def render
|
|
9
|
+
attrs = {}
|
|
10
|
+
[:id, :class].each do |key|
|
|
11
|
+
if options.include?(key)
|
|
12
|
+
value = options[key]
|
|
13
|
+
attrs[key] = value unless value.blank?
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# We can't use content_tag with a block (no self.output_buffer)
|
|
18
|
+
# so we pass in content
|
|
19
|
+
container attrs, angular_error_list_html
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def options
|
|
25
|
+
@_options ||= @options.symbolize_keys
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def container(attrs, content)
|
|
29
|
+
content_tag :ul, content, attrs.merge(container_attrs)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def angular_error_list_html
|
|
33
|
+
validators.map do |validator|
|
|
34
|
+
mapper = validator_mapper_for(validator)
|
|
35
|
+
mapper.error_messages.map do |error_type, msg|
|
|
36
|
+
content_tag :li, msg, 'ng-show' => "#{angular_form_field_object_name}.$error.#{error_type}"
|
|
37
|
+
end.join
|
|
38
|
+
end.join.html_safe
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def container_attrs
|
|
42
|
+
ng_show = configuration.validate_show_condition % {
|
|
43
|
+
model: @object_name,
|
|
44
|
+
form: angular_form_object_name,
|
|
45
|
+
field: angular_form_field_object_name,
|
|
46
|
+
validate_on: validate_on || 'true'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
{
|
|
50
|
+
'ng-show' => ng_show
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def validate_on
|
|
55
|
+
field = angular_form_field_object_name
|
|
56
|
+
form = angular_form_object_name
|
|
57
|
+
|
|
58
|
+
configuration.validate_on.inject('') do |str, (kind, op)|
|
|
59
|
+
op = case op
|
|
60
|
+
when :and
|
|
61
|
+
' && '
|
|
62
|
+
when :or
|
|
63
|
+
' || '
|
|
64
|
+
else
|
|
65
|
+
''
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
str << (kind == :submit_attempt ? "#{form}.$#{kind}" : "#{field}.$#{kind}") << op
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
module Helpers
|
|
4
|
+
module Tags
|
|
5
|
+
module TagCommon
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
include Forwardable
|
|
8
|
+
|
|
9
|
+
protected
|
|
10
|
+
|
|
11
|
+
delegate :configuration, to: Rails::Angulate
|
|
12
|
+
|
|
13
|
+
def angular_form_object_name
|
|
14
|
+
@template_object.ng_form_name(object)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def angular_form_field_object_name
|
|
18
|
+
@template_object.ng_form_field_name(object, @method_name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validators
|
|
22
|
+
@validators ||=
|
|
23
|
+
object.class.validators.select { |v| v.attributes.include?(@method_name.to_sym) }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def validator_mapper_for(validator)
|
|
27
|
+
Rails::Angulate::Mappers.create_validator_mapper_for(object, @method_name, validator)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'rails/angulate/mappers/base'
|
|
2
|
+
|
|
3
|
+
module Rails
|
|
4
|
+
module Angulate
|
|
5
|
+
module Mappers
|
|
6
|
+
@@lock = Mutex.new
|
|
7
|
+
@@mappers = {}
|
|
8
|
+
|
|
9
|
+
def self.register_mapper(constant, kind = nil)
|
|
10
|
+
@@lock.synchronize do
|
|
11
|
+
if kind.nil?
|
|
12
|
+
kind = constant.name.split('::').last
|
|
13
|
+
.sub('ValidatorMapper', '').underscore
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@@mappers[kind.to_sym] = constant unless kind.blank?
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.create_validator_mapper_for(model, attribute_name, validator)
|
|
21
|
+
@@lock.synchronize do
|
|
22
|
+
if klass = @@mappers[validator.kind]
|
|
23
|
+
klass.new(model, attribute_name, validator)
|
|
24
|
+
else
|
|
25
|
+
# General purpose mapper
|
|
26
|
+
ValidatorMapper.new(model, attribute_name, validator)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
require 'rails/angulate/mappers/validator_mapper'
|
|
36
|
+
require 'rails/angulate/mappers/length_validator_mapper'
|
|
37
|
+
require 'rails/angulate/mappers/format_validator_mapper'
|
|
38
|
+
require 'rails/angulate/mappers/numericality_validator_mapper'
|
|
39
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
module Mappers
|
|
4
|
+
class Base
|
|
5
|
+
attr_reader :validator, :model, :attribute
|
|
6
|
+
|
|
7
|
+
def self.inherited(mapper)
|
|
8
|
+
Mappers.register_mapper(mapper)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
delegate :configuration, to: Rails::Angulate
|
|
12
|
+
|
|
13
|
+
def initialize(model, attribute, validator)
|
|
14
|
+
@model = model
|
|
15
|
+
@attribute = attribute
|
|
16
|
+
@validator = validator
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def error_messages
|
|
20
|
+
[]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def full_message(message)
|
|
24
|
+
return message if attribute == :base
|
|
25
|
+
attr_name = attribute.to_s.tr('.', '_').humanize
|
|
26
|
+
attr_name = @model.class.human_attribute_name(attribute, default: attribute.to_s.humanize)
|
|
27
|
+
with_i18n do |locale|
|
|
28
|
+
locale.t(:format, {
|
|
29
|
+
default: "%{attribute} %{message}",
|
|
30
|
+
attribute: attr_name,
|
|
31
|
+
message: message
|
|
32
|
+
})
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def error_messages
|
|
37
|
+
default_message = validator_options[:message]
|
|
38
|
+
|
|
39
|
+
with_i18n do |locale|
|
|
40
|
+
{
|
|
41
|
+
kind_to_ng(validator.kind) => default_message || locale.t(:"messages.#{validator.kind}", {
|
|
42
|
+
model: model.class.name.humanize,
|
|
43
|
+
attribute: attribute
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
protected
|
|
50
|
+
|
|
51
|
+
def translate_params
|
|
52
|
+
{
|
|
53
|
+
model: model.class.name.humanize,
|
|
54
|
+
attribute: attribute.to_s.humanize,
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def kind_to_ng(kind)
|
|
59
|
+
configuration.validator_mappings[kind] || kind
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def mapped_kind
|
|
63
|
+
kind = validator.kind
|
|
64
|
+
configuration.validator_mappings[kind] || kind
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def with_i18n(options = {}, &block)
|
|
68
|
+
I18n.with_options scope: [:angulate, :errors], &block
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def validator_options
|
|
72
|
+
validator.options
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
module Mappers
|
|
4
|
+
class FormatValidatorMapper < Base
|
|
5
|
+
def ng_attributes
|
|
6
|
+
{}.tap do |attrs|
|
|
7
|
+
if pattern = validator_options[:javascript_format]
|
|
8
|
+
attrs["ng-pattern"] = pattern
|
|
9
|
+
elsif pattern = validator_options[:with]
|
|
10
|
+
attrs["ng-pattern"] = javascriptify_pattern(pattern.source)
|
|
11
|
+
elsif validator_options[:without]
|
|
12
|
+
ActiveSupport::Deprecation.warn(<<-TEXT.strip)
|
|
13
|
+
Angulate does not support validates_format validation using the without option.
|
|
14
|
+
Use the 'with' and/or 'javascript_format' options instead.
|
|
15
|
+
TEXT
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Will only work with simple regexes that happen to match javascript.
|
|
24
|
+
# Replaces leading \A and trailing \z with ^ and $ respectively
|
|
25
|
+
def javascriptify_pattern(pattern)
|
|
26
|
+
pattern.gsub!(/^\\A/, '^')
|
|
27
|
+
pattern.gsub!(/\\z$/, '$')
|
|
28
|
+
"/#{pattern}/"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
module Mappers
|
|
4
|
+
class LengthValidatorMapper < Base
|
|
5
|
+
OPTION_MAP = { is: :islength, minimum: :minlength, maximum: :maxlength }.freeze
|
|
6
|
+
|
|
7
|
+
def ng_attributes
|
|
8
|
+
opts = validator_options
|
|
9
|
+
{}.tap do |attrs|
|
|
10
|
+
validator_options.each do |key, value|
|
|
11
|
+
attrs["ng-#{OPTION_MAP[key]}"] = opts[key] if opts[key].present?
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def error_messages
|
|
17
|
+
messages = {}
|
|
18
|
+
default_message = validator_options[:message]
|
|
19
|
+
|
|
20
|
+
with_i18n do |locale|
|
|
21
|
+
validator.class::MESSAGES.each do |key, msg|
|
|
22
|
+
if default_message.nil?
|
|
23
|
+
next unless validator_options[key]
|
|
24
|
+
|
|
25
|
+
count = validator_options[key]
|
|
26
|
+
|
|
27
|
+
message = locale.t(
|
|
28
|
+
:"messages.#{msg}",
|
|
29
|
+
model: model.class.name.humanize,
|
|
30
|
+
attribute: attribute.to_s.humanize,
|
|
31
|
+
count: count
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
messages[OPTION_MAP[key]] = full_message(message)
|
|
35
|
+
else
|
|
36
|
+
messages[OPTION_MAP[key]] = default_message
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
messages
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
module Rails
|
|
2
|
+
module Angulate
|
|
3
|
+
module Mappers
|
|
4
|
+
class NumericalityValidatorMapper < Base
|
|
5
|
+
CHECKS = ActiveModel::Validations::NumericalityValidator::CHECKS
|
|
6
|
+
|
|
7
|
+
def ng_attributes
|
|
8
|
+
{}.tap do |attrs|
|
|
9
|
+
attrs["ang-validator"] = "numericality"
|
|
10
|
+
attrs["ang-valid-if"] = numericality_conditions.to_json
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def error_messages
|
|
15
|
+
messages = {}
|
|
16
|
+
default_message = validator_options[:message]
|
|
17
|
+
|
|
18
|
+
default_message || with_i18n do |locale|
|
|
19
|
+
numericality_options.each do |option, option_value|
|
|
20
|
+
messages[option] = full_message(
|
|
21
|
+
locale.t :"messages.#{option}",
|
|
22
|
+
translate_params.merge(count: option_value)
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
if allow_only_integer?
|
|
26
|
+
messages[:only_integer] = full_message(
|
|
27
|
+
locale.t :"messages.not_an_integer",
|
|
28
|
+
translate_params.merge(count: option_value)
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
messages
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
protected
|
|
38
|
+
|
|
39
|
+
def numericality_conditions
|
|
40
|
+
numericality_options.inject({}) do |hash, (option, option_value)|
|
|
41
|
+
case option
|
|
42
|
+
when :odd
|
|
43
|
+
hash[option] = "value % 2 != 0"
|
|
44
|
+
when :even
|
|
45
|
+
hash[option] = "value % 2 == 0"
|
|
46
|
+
else
|
|
47
|
+
case option_value
|
|
48
|
+
when Proc
|
|
49
|
+
option_value = option_value.call(record)
|
|
50
|
+
when Symbol
|
|
51
|
+
option_value = record.send(option_value)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
op = CHECKS[option]
|
|
55
|
+
|
|
56
|
+
hash[option] = "value #{op} #{option_value}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# TODO: hmm, neither isNaN nor a Regex work when called with scope.$eval
|
|
60
|
+
hash[:only_integer] = %q{!isNaN(+value)} if allow_only_integer?
|
|
61
|
+
|
|
62
|
+
hash
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def allow_only_integer?
|
|
67
|
+
case validator_options[:only_integer]
|
|
68
|
+
when Symbol
|
|
69
|
+
model.send(validator_options[:only_integer])
|
|
70
|
+
when Proc
|
|
71
|
+
validator_options[:only_integer].call(model)
|
|
72
|
+
else
|
|
73
|
+
!!validator_options[:only_integer]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def numericality_options
|
|
78
|
+
@numericality_options ||= validator_options.slice(*CHECKS.keys)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'rails'
|
|
2
|
+
require 'angulate/helpers'
|
|
3
|
+
|
|
4
|
+
module Rails
|
|
5
|
+
module Angulate
|
|
6
|
+
class Railtie < ::Rails::Railtie
|
|
7
|
+
initializer :include_helpers do |app|
|
|
8
|
+
ActiveSupport.on_load(:action_view) do
|
|
9
|
+
include Rails::Angulate::Helpers
|
|
10
|
+
cattr_accessor(:default_form_builder) { Rails::Angulate::Helpers::FormBuilder }
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rails-angulate
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Stan Bondi
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-06-28 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '4'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '4'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.6'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.6'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
description: Angulate adds AngularJS client-side field and validation helpers to Rails
|
|
56
|
+
form helpers.
|
|
57
|
+
email:
|
|
58
|
+
- stan@fixate.it
|
|
59
|
+
executables: []
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- Gemfile
|
|
64
|
+
- LICENSE.txt
|
|
65
|
+
- README.md
|
|
66
|
+
- Rakefile
|
|
67
|
+
- lib/rails-angulate.rb
|
|
68
|
+
- lib/rails/angulate.rb
|
|
69
|
+
- lib/rails/angulate/configuration.rb
|
|
70
|
+
- lib/rails/angulate/engine.rb
|
|
71
|
+
- lib/rails/angulate/helpers.rb
|
|
72
|
+
- lib/rails/angulate/helpers/form_builder.rb
|
|
73
|
+
- lib/rails/angulate/helpers/form_helper.rb
|
|
74
|
+
- lib/rails/angulate/helpers/tags.rb
|
|
75
|
+
- lib/rails/angulate/helpers/tags/ng_email_field.rb
|
|
76
|
+
- lib/rails/angulate/helpers/tags/ng_text_field.rb
|
|
77
|
+
- lib/rails/angulate/helpers/tags/ng_validation_errors.rb
|
|
78
|
+
- lib/rails/angulate/helpers/tags/tag_common.rb
|
|
79
|
+
- lib/rails/angulate/mappers.rb
|
|
80
|
+
- lib/rails/angulate/mappers/base.rb
|
|
81
|
+
- lib/rails/angulate/mappers/format_validator_mapper.rb
|
|
82
|
+
- lib/rails/angulate/mappers/length_validator_mapper.rb
|
|
83
|
+
- lib/rails/angulate/mappers/numericality_validator_mapper.rb
|
|
84
|
+
- lib/rails/angulate/mappers/validator_mapper.rb
|
|
85
|
+
- lib/rails/angulate/railtie.rb
|
|
86
|
+
- lib/rails/angulate/version.rb
|
|
87
|
+
homepage: https://github.com/fixate/rails-angulate
|
|
88
|
+
licenses:
|
|
89
|
+
- MIT
|
|
90
|
+
metadata: {}
|
|
91
|
+
post_install_message:
|
|
92
|
+
rdoc_options: []
|
|
93
|
+
require_paths:
|
|
94
|
+
- lib
|
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '0'
|
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
|
+
requirements:
|
|
102
|
+
- - ">="
|
|
103
|
+
- !ruby/object:Gem::Version
|
|
104
|
+
version: '0'
|
|
105
|
+
requirements: []
|
|
106
|
+
rubyforge_project:
|
|
107
|
+
rubygems_version: 2.2.2
|
|
108
|
+
signing_key:
|
|
109
|
+
specification_version: 4
|
|
110
|
+
summary: AngularJS Rails form helpers.
|
|
111
|
+
test_files: []
|