rails-angulate 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|