formalist 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/.travis.yml +21 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +62 -0
- data/Gemfile +1 -2
- data/bin/console +13 -0
- data/formalist.gemspec +33 -0
- data/lib/formalist/definition.rb +65 -0
- data/lib/formalist/element/class_interface.rb +7 -59
- data/lib/formalist/element.rb +37 -19
- data/lib/formalist/elements/attr.rb +8 -20
- data/lib/formalist/elements/compound_field.rb +5 -4
- data/lib/formalist/elements/field.rb +5 -12
- data/lib/formalist/elements/group.rb +6 -5
- data/lib/formalist/elements/many.rb +28 -29
- data/lib/formalist/elements/section.rb +6 -10
- data/lib/formalist/elements/standard/multi_upload_field.rb +8 -0
- data/lib/formalist/elements/standard/rich_text_area.rb +40 -0
- data/lib/formalist/elements/standard/search_multi_selection_field.rb +20 -0
- data/lib/formalist/elements/standard/search_selection_field.rb +20 -0
- data/lib/formalist/elements/standard/tags_field.rb +16 -0
- data/lib/formalist/elements/standard/upload_field.rb +8 -0
- data/lib/formalist/elements/standard.rb +4 -0
- data/lib/formalist/form/validity_check.rb +54 -0
- data/lib/formalist/form.rb +49 -17
- data/lib/formalist/rich_text/embedded_form_compiler.rb +86 -0
- data/lib/formalist/rich_text/embedded_forms_container/mixin.rb +42 -0
- data/lib/formalist/rich_text/embedded_forms_container/registration.rb +30 -0
- data/lib/formalist/rich_text/embedded_forms_container.rb +9 -0
- data/lib/formalist/rich_text/rendering/embedded_form_renderer.rb +25 -0
- data/lib/formalist/rich_text/rendering/html_compiler.rb +100 -0
- data/lib/formalist/rich_text/rendering/html_renderer.rb +186 -0
- data/lib/formalist/rich_text/validity_check.rb +48 -0
- data/lib/formalist/types.rb +8 -7
- data/lib/formalist/version.rb +1 -1
- metadata +54 -31
- data/Gemfile.lock +0 -105
- data/lib/formalist/element/definition.rb +0 -55
- data/lib/formalist/element/permitted_children.rb +0 -46
- data/lib/formalist/form/definition_context.rb +0 -69
- data/lib/formalist/form/result.rb +0 -24
- data/spec/examples.txt +0 -8
- data/spec/integration/dependency_injection_spec.rb +0 -54
- data/spec/integration/form_spec.rb +0 -104
- data/spec/spec_helper.rb +0 -109
- data/spec/support/constants.rb +0 -11
- data/spec/unit/elements/standard/check_box_spec.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1ef816ca82a212ab5b8eba60fd57c68393d1443876b527b85b507c933974fdb9
|
4
|
+
data.tar.gz: 539b605da36b8383a5645fd191920e9c16c7ff7c6f1582dc435bf521a96366a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c23dd6b7f40ead5fa9fd81008bef073a7b94fe3e98738f3a03a22733e7a732b5e1ba92e0ec26cc66cf41380a96155c643144e90f450500f8039e8fa0e663087
|
7
|
+
data.tar.gz: e58de764348c401f5321864f761e421415536a31e607ea13567d2e0374c563125162c395f4ed0d70488c026c44b841f655fd43fba359e8cc18565a0349f3aa39
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
language: ruby
|
2
|
+
dist: trusty
|
3
|
+
sudo: false
|
4
|
+
cache: bundler
|
5
|
+
before_install:
|
6
|
+
- gem update bundler
|
7
|
+
script:
|
8
|
+
- bundle exec rake
|
9
|
+
after_success:
|
10
|
+
# Send coverage report from the job #1 == current MRI release
|
11
|
+
- '[ "${TRAVIS_JOB_NUMBER#*.}" = "1" ] && [ "$TRAVIS_BRANCH" = "master" ] && bundle exec codeclimate-test-reporter'
|
12
|
+
rvm:
|
13
|
+
- 2.4.0
|
14
|
+
- 2.3.3
|
15
|
+
- 2.2.6
|
16
|
+
- jruby-9.1.6.0
|
17
|
+
addons:
|
18
|
+
code_climate:
|
19
|
+
repo_token: 2c2c7c253435c02667371778ca886b069d4d24590748fbd7396b9b080016bfa7
|
20
|
+
notifications:
|
21
|
+
email: false
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup=markdown
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# 0.4.0 / 2018-03-28
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
- `rich_text_area` field type, support for embedding and validating forms within rich text areas, and rendering the rich text from its native draft.js AST format to HTML
|
6
|
+
- `search_selection_field` and `multi_search_selection_field` field types
|
7
|
+
- Various improvements to the upload fields, including support for passing `presign_options`
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
- [BREAKING] Form definition blocks are now evaluated within the context of the form instance's `self`, which mean dependencies can be injected into the form object and accessed from the form definition block. `#dep` within the definition block has thusly been removed.
|
12
|
+
- [BREAKING] `Formalist::Form` should now be instantiated (`form = MyForm.new`) and then filled with `form.fill(input: input_data, errors: error_messages)`. `Form#fill` returns a copy of the form object with all the elements filled with the input data and error messages as required. `Form#call` has been removed, along with `Formalist::Form::Result` (which was the object returned from `#call`).
|
13
|
+
|
14
|
+
### Removed
|
15
|
+
|
16
|
+
- Form elements no longer have a `permitted_children` config. For now, this should be handled by convention only.
|
17
|
+
|
18
|
+
# 0.3.0 / 2016-05-04
|
19
|
+
|
20
|
+
Add support for upload and multi upload fields.
|
21
|
+
|
22
|
+
# 0.2.3 / 2016-04-07
|
23
|
+
|
24
|
+
Default check_box element values to false.
|
25
|
+
|
26
|
+
# 0.2.2 / 2016-02-23
|
27
|
+
|
28
|
+
Remove local type coercion using dry-data. We rely on a `Dry::Validation::Schema` to do this now. The form definition API has not yet changed, though. We still require field types to be specified, but there is no longer any restriction over what is entered. We'll remove this in a future release, once we can infer types from the schema.
|
29
|
+
|
30
|
+
# 0.2.1 / 2016-02-23
|
31
|
+
|
32
|
+
Fix issue where form could not be built with input data with native data types (it presuming input would be HTML form-style input everywhere).
|
33
|
+
|
34
|
+
Add default (empty) input data argument for `Form#build`. This allows you simply to call `MyForm.build` for creating a "new" form (i.e. one without any existing input data).
|
35
|
+
|
36
|
+
# 0.2.0 / 2016-02-22
|
37
|
+
|
38
|
+
Require a dry-validation schema for each form. The schema should completely represent the form's expected data structure.
|
39
|
+
|
40
|
+
Update the API to better support the two main use cases for a form. First, to prepare a form with sane, initial input from your database and send it to a view for rendering:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
my_form = MyForm.new(my_schema)
|
44
|
+
my_form.build(input) # returns a `Formalist::Form::Result`
|
45
|
+
```
|
46
|
+
|
47
|
+
Then, to receive the data from the posted form, coerce it and validate it (and potentially re-display the form with errors):
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
my_form = MyForm.new(my_schema)
|
51
|
+
my_form.receive(input).validate # returns a `Formalist::Form::ValidatedResult`
|
52
|
+
```
|
53
|
+
|
54
|
+
The main differences are as such:
|
55
|
+
|
56
|
+
* `#build` expects already-clean (e.g. properly structured and typed) data
|
57
|
+
* `#receive` expects the kind of data that your form will submit, and will then coerce it according to the validation schema, and then send the sanitised output to `#build`
|
58
|
+
* Calling `#validate` on a result object will validate the input data and include any error messages in its AST
|
59
|
+
|
60
|
+
# 0.1.0 / 2016-01-18
|
61
|
+
|
62
|
+
Initial release.
|
data/Gemfile
CHANGED
@@ -5,8 +5,7 @@ gemspec
|
|
5
5
|
group :test do
|
6
6
|
gem "codeclimate-test-reporter", require: nil
|
7
7
|
gem "dry-auto_inject"
|
8
|
-
gem "dry-validation",
|
9
|
-
gem "dry-types", git: "https://github.com/dryrb/dry-types", branch: "master"
|
8
|
+
gem "dry-validation", "~> 0.11"
|
10
9
|
end
|
11
10
|
|
12
11
|
group :tools do
|
data/bin/console
ADDED
data/formalist.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "formalist/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "formalist"
|
7
|
+
spec.version = Formalist::VERSION
|
8
|
+
spec.authors = ["Tim Riley"]
|
9
|
+
spec.email = ["tim@icelab.com.au"]
|
10
|
+
spec.license = "MIT"
|
11
|
+
|
12
|
+
spec.summary = "Flexible form builder"
|
13
|
+
spec.homepage = "https://github.com/icelab/formalist"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
+
spec.bindir = 'exe'
|
17
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.required_ruby_version = ">= 2.2.0"
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "dry-configurable", "~> 0.7"
|
23
|
+
spec.add_runtime_dependency "dry-core", "~> 0.4"
|
24
|
+
spec.add_runtime_dependency "dry-container", "~> 0.6"
|
25
|
+
spec.add_runtime_dependency "dry-types", "~> 0.12"
|
26
|
+
spec.add_runtime_dependency "inflecto"
|
27
|
+
|
28
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
29
|
+
spec.add_development_dependency "rake", "~> 10.4.2"
|
30
|
+
spec.add_development_dependency "rspec", "~> 3.3.0"
|
31
|
+
spec.add_development_dependency "simplecov", "~> 0.13.0"
|
32
|
+
spec.add_development_dependency "yard"
|
33
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Formalist
|
2
|
+
class Definition
|
3
|
+
DuplicateElementError = Class.new(StandardError)
|
4
|
+
|
5
|
+
attr_reader :form
|
6
|
+
attr_reader :config
|
7
|
+
attr_reader :elements
|
8
|
+
|
9
|
+
def initialize(form, config, &block)
|
10
|
+
@form = form
|
11
|
+
@config = config
|
12
|
+
@elements = []
|
13
|
+
|
14
|
+
instance_eval(&block) if block
|
15
|
+
end
|
16
|
+
|
17
|
+
def with(**new_options, &block)
|
18
|
+
new_config = new_options.each_with_object(config.dup) { |(key, value), config|
|
19
|
+
config.send :"#{key}=", value
|
20
|
+
}
|
21
|
+
|
22
|
+
self.class.new(form, new_config, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(name, *args, &block)
|
26
|
+
if element_type?(name)
|
27
|
+
add_element(name, *args, &block)
|
28
|
+
elsif form.respond_to?(name)
|
29
|
+
form.send(name, *args, &block)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def respond_to_missing?(name, _include_private = false)
|
38
|
+
element_type?(name) || form.respond_to?(name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def element_type?(type)
|
42
|
+
config.elements_container.key?(type)
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_element(type, *args, &block)
|
46
|
+
element_name = args.shift unless args.first.is_a?(Hash)
|
47
|
+
element_attrs = args.last.is_a?(Hash) ? args.last : {}
|
48
|
+
|
49
|
+
if element_name && elements.any? { |element| element.name == element_name }
|
50
|
+
raise DuplicateElementError, "element +#{element_name}+ is already defined in this context"
|
51
|
+
end
|
52
|
+
|
53
|
+
element_class = config.elements_container[type]
|
54
|
+
element_children = with(&block).elements
|
55
|
+
|
56
|
+
element = element_class.build(
|
57
|
+
name: element_name,
|
58
|
+
attributes: element_attrs,
|
59
|
+
children: element_children,
|
60
|
+
)
|
61
|
+
|
62
|
+
elements << element
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -1,28 +1,23 @@
|
|
1
1
|
require "inflecto"
|
2
|
-
require "formalist/element/permitted_children"
|
3
2
|
|
4
3
|
module Formalist
|
5
4
|
class Element
|
6
5
|
# Class-level API for form elements.
|
7
6
|
module ClassInterface
|
8
|
-
# Returns the element's type, which is a symbolized,
|
7
|
+
# Returns the element's type, which is a symbolized, underscored
|
9
8
|
# representation of the element's class name.
|
10
9
|
#
|
11
|
-
# This is
|
12
|
-
#
|
13
|
-
#
|
10
|
+
# This is important for form rendering when using custom form elements,
|
11
|
+
# since the type in this case will be based on the name of form element's
|
12
|
+
# sublass.
|
14
13
|
#
|
15
|
-
# @example Basic element
|
16
|
-
# Formalist::Elements::Field.type # => :field
|
14
|
+
# @example Basic element Formalist::Elements::Field.type # => :field
|
17
15
|
#
|
18
|
-
# @example Custom element
|
19
|
-
# class MyField < Formalist::Elements::Field
|
20
|
-
# end
|
16
|
+
# @example Custom element class MyField < Formalist::Elements::Field end
|
21
17
|
#
|
22
18
|
# MyField.type # => :my_field
|
23
19
|
#
|
24
|
-
# @!scope class
|
25
|
-
# @return [Symbol] the element type.
|
20
|
+
# @!scope class @return [Symbol] the element type.
|
26
21
|
def type
|
27
22
|
Inflecto.underscore(Inflecto.demodulize(name)).to_sym
|
28
23
|
end
|
@@ -71,53 +66,6 @@ module Formalist
|
|
71
66
|
super_schema.merge(@attributes_schema || {})
|
72
67
|
end
|
73
68
|
|
74
|
-
# Sets or fetches the policy for the element's permitted child form elements.
|
75
|
-
#
|
76
|
-
# @overload permitted_children(policy)
|
77
|
-
# Set a policy for whether the element permits child form elements.
|
78
|
-
#
|
79
|
-
# Specify `:all` to allow all children, or `:none` to permit no
|
80
|
-
# children.
|
81
|
-
#
|
82
|
-
# @example Permitting all children
|
83
|
-
# permitted_children :all
|
84
|
-
#
|
85
|
-
# @example Permitting no children
|
86
|
-
# permitted_children :none
|
87
|
-
#
|
88
|
-
# @return void
|
89
|
-
#
|
90
|
-
# @overload permitted_children(element_type, ...)
|
91
|
-
# Permit the element to contain only the specified element types as children.
|
92
|
-
#
|
93
|
-
# @example
|
94
|
-
# permit_children :section, :field
|
95
|
-
#
|
96
|
-
# @param element_type [Symbol] the name of a child element type to permit
|
97
|
-
# @param ... [Symbol] more child element types to permit
|
98
|
-
# @return void
|
99
|
-
#
|
100
|
-
# @overload permitted_children
|
101
|
-
# Returns the permitted child element types for the element.
|
102
|
-
#
|
103
|
-
# If no `permitted_children` policy was previously specified, then it
|
104
|
-
# allows all children by default.
|
105
|
-
#
|
106
|
-
# @return [#permitted?] permissions object.
|
107
|
-
#
|
108
|
-
# @see Formalist::Element::PermittedChildren
|
109
|
-
#
|
110
|
-
# @!scope class
|
111
|
-
def permitted_children(*args)
|
112
|
-
return @permitted_children ||= PermittedChildren.all if args.empty?
|
113
|
-
|
114
|
-
@permitted_children = if %i[all none].include?(args.first)
|
115
|
-
PermittedChildren.send(args.first)
|
116
|
-
else
|
117
|
-
PermittedChildren[args]
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
69
|
private
|
122
70
|
|
123
71
|
# @!scope class
|
data/lib/formalist/element.rb
CHANGED
@@ -7,42 +7,60 @@ module Formalist
|
|
7
7
|
extend ClassInterface
|
8
8
|
|
9
9
|
# @api private
|
10
|
-
attr_reader :attributes, :children, :input, :errors
|
10
|
+
attr_reader :name, :attributes, :children, :input, :errors
|
11
11
|
|
12
12
|
# @api private
|
13
|
-
def
|
13
|
+
def self.build(**args)
|
14
|
+
new(args)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
def self.fill(input: {}, errors: {}, **args)
|
19
|
+
new(args).fill(input: input, errors: errors)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @api private
|
23
|
+
def initialize(name: nil, attributes: {}, children: [], input: nil, errors: [])
|
24
|
+
@name = Types::ElementName[name]
|
25
|
+
|
14
26
|
# Set supplied attributes or their defaults
|
15
|
-
|
27
|
+
all_attributes = self.class.attributes_schema.each_with_object({}) { |(name, defn), memo|
|
16
28
|
value = attributes[name] || defn[:default]
|
17
29
|
memo[name] = value unless value.nil?
|
18
30
|
}
|
19
31
|
|
20
32
|
# Then run them through the schema
|
21
|
-
@attributes = Types::Hash.schema(
|
33
|
+
@attributes = Types::Hash.schema(
|
34
|
+
self.class.attributes_schema.map { |name, defn| [name, defn[:type]] }.to_h
|
35
|
+
)[all_attributes]
|
22
36
|
|
23
|
-
@children =
|
37
|
+
@children = children
|
24
38
|
@input = input
|
25
39
|
@errors = errors
|
26
40
|
end
|
27
41
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
+
def fill(input: {}, errors: {}, **args)
|
43
|
+
return self if input == @input && errors == @errors
|
44
|
+
|
45
|
+
args = {
|
46
|
+
name: @name,
|
47
|
+
attributes: @attributes,
|
48
|
+
children: @children,
|
49
|
+
input: input,
|
50
|
+
errors: errors,
|
51
|
+
}.merge(args)
|
52
|
+
|
53
|
+
self.class.new(args)
|
54
|
+
end
|
55
|
+
|
42
56
|
def type
|
43
57
|
self.class.type
|
44
58
|
end
|
45
59
|
|
60
|
+
def ==(other)
|
61
|
+
name && type == other.type && name == other.name
|
62
|
+
end
|
63
|
+
|
46
64
|
# @abstract
|
47
65
|
def to_ast
|
48
66
|
raise NotImplementedError
|
@@ -4,21 +4,17 @@ require "formalist/types"
|
|
4
4
|
module Formalist
|
5
5
|
class Elements
|
6
6
|
class Attr < Element
|
7
|
-
permitted_children :all
|
8
|
-
|
9
|
-
# @api private
|
10
|
-
attr_reader :name
|
11
|
-
|
12
7
|
attribute :label, Types::String
|
13
8
|
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
def fill(input:, errors:)
|
10
|
+
input = input[name] || {}
|
11
|
+
errors = errors[name] || {}
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
13
|
+
children = self.children.map { |child|
|
14
|
+
child.fill(input: input, errors: errors)
|
15
|
+
}
|
16
|
+
|
17
|
+
super(input: input, errors: errors, children: children)
|
22
18
|
end
|
23
19
|
|
24
20
|
# Converts the attribute into an abstract syntax tree.
|
@@ -61,14 +57,6 @@ module Formalist
|
|
61
57
|
children.map(&:to_ast),
|
62
58
|
]]
|
63
59
|
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def build_children(definitions)
|
68
|
-
child_errors = errors.is_a?(Hash) ? errors : {}
|
69
|
-
|
70
|
-
definitions.map { |definition| definition.(input, child_errors) }
|
71
|
-
end
|
72
60
|
end
|
73
61
|
end
|
74
62
|
end
|
@@ -4,11 +4,12 @@ require "formalist/types"
|
|
4
4
|
module Formalist
|
5
5
|
class Elements
|
6
6
|
class CompoundField < Element
|
7
|
-
|
7
|
+
def fill(input: {}, errors: {})
|
8
|
+
children = self.children.map { |child|
|
9
|
+
child.fill(input: input, errors: errors)
|
10
|
+
}
|
8
11
|
|
9
|
-
|
10
|
-
super
|
11
|
-
@children = children.map { |definition| definition.(input, errors) }
|
12
|
+
super(input: input, errors: errors, children: children)
|
12
13
|
end
|
13
14
|
|
14
15
|
# Converts the compound field into an abstract syntax tree.
|
@@ -4,11 +4,6 @@ require "formalist/types"
|
|
4
4
|
module Formalist
|
5
5
|
class Elements
|
6
6
|
class Field < Element
|
7
|
-
permitted_children :none
|
8
|
-
|
9
|
-
# @api private
|
10
|
-
attr_reader :name
|
11
|
-
|
12
7
|
attribute :label, Types::String
|
13
8
|
attribute :hint, Types::String
|
14
9
|
attribute :placeholder, Types::String
|
@@ -18,13 +13,11 @@ module Formalist
|
|
18
13
|
# @api private
|
19
14
|
attr_reader :predicates
|
20
15
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
@input = input[@name] if input
|
27
|
-
@errors = errors[@name].to_a
|
16
|
+
def fill(input: {}, errors: {})
|
17
|
+
super(
|
18
|
+
input: input[name],
|
19
|
+
errors: errors[name].to_a,
|
20
|
+
)
|
28
21
|
end
|
29
22
|
|
30
23
|
# Converts the field into an abstract syntax tree.
|
@@ -4,13 +4,14 @@ require "formalist/types"
|
|
4
4
|
module Formalist
|
5
5
|
class Elements
|
6
6
|
class Group < Element
|
7
|
-
permitted_children :attr, :compound_field, :field, :many
|
8
|
-
|
9
7
|
attribute :label, Types::String
|
10
8
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
9
|
+
def fill(input: {}, errors: {})
|
10
|
+
children = self.children.map { |child|
|
11
|
+
child.fill(input: input, errors: errors)
|
12
|
+
}
|
13
|
+
|
14
|
+
super(input: input, errors: errors, children: children)
|
14
15
|
end
|
15
16
|
|
16
17
|
# Converts the group into an abstract syntax tree.
|
@@ -4,11 +4,6 @@ require "formalist/types"
|
|
4
4
|
module Formalist
|
5
5
|
class Elements
|
6
6
|
class Many < Element
|
7
|
-
permitted_children :attr, :compound_field, :group, :field
|
8
|
-
|
9
|
-
# @api private
|
10
|
-
attr_reader :name
|
11
|
-
|
12
7
|
attribute :label, Types::String
|
13
8
|
attribute :action_label, Types::String
|
14
9
|
attribute :placeholder, Types::String
|
@@ -18,14 +13,35 @@ module Formalist
|
|
18
13
|
attr_reader :child_template
|
19
14
|
|
20
15
|
# @api private
|
21
|
-
def
|
22
|
-
|
16
|
+
def self.build(children: [], **args)
|
17
|
+
child_template = children.dup
|
18
|
+
super(child_template: child_template, **args)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @api private
|
22
|
+
def initialize(child_template:, **args)
|
23
|
+
@child_template = child_template
|
24
|
+
super(**args)
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def fill(input: {}, errors: {})
|
29
|
+
input = input.fetch(name) { [] }
|
30
|
+
errors = errors.fetch(name) { {} }
|
31
|
+
|
32
|
+
children = input.each_with_index.map { |child_input, index|
|
33
|
+
# Child errors look like this: {0=>{:summary=>["must be filled"]}
|
34
|
+
child_errors = errors.fetch(index) { {} }
|
23
35
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
36
|
+
child_template.map { |child| child.fill(input: child_input, errors: child_errors) }
|
37
|
+
}
|
38
|
+
|
39
|
+
super(
|
40
|
+
input: input,
|
41
|
+
errors: errors,
|
42
|
+
children: children,
|
43
|
+
child_template: child_template,
|
44
|
+
)
|
29
45
|
end
|
30
46
|
|
31
47
|
# Until we can put defaults on `Types::Bool`, supply them here
|
@@ -103,23 +119,6 @@ module Formalist
|
|
103
119
|
children.map { |el_list| el_list.map(&:to_ast) },
|
104
120
|
]]
|
105
121
|
end
|
106
|
-
|
107
|
-
private
|
108
|
-
|
109
|
-
def build_child_template(definitions)
|
110
|
-
definitions.map { |el| el.({}, {})}
|
111
|
-
end
|
112
|
-
|
113
|
-
def build_children(definitions)
|
114
|
-
# Child errors look like this: {0=>{:summary=>["must be filled"]}
|
115
|
-
child_errors = errors.is_a?(Hash) ? errors : {}
|
116
|
-
|
117
|
-
input.each_with_index.map { |child_input, index|
|
118
|
-
errors = child_errors.fetch(index, {})
|
119
|
-
|
120
|
-
definitions.map { |el| el.(child_input, errors) }
|
121
|
-
}
|
122
|
-
end
|
123
122
|
end
|
124
123
|
end
|
125
124
|
end
|
@@ -4,18 +4,14 @@ require "formalist/types"
|
|
4
4
|
module Formalist
|
5
5
|
class Elements
|
6
6
|
class Section < Element
|
7
|
-
permitted_children :all
|
8
|
-
|
9
|
-
# @api private
|
10
|
-
attr_reader :name
|
11
|
-
|
12
7
|
attribute :label, Types::String
|
13
8
|
|
14
|
-
def
|
15
|
-
super
|
16
|
-
|
17
|
-
|
18
|
-
|
9
|
+
def fill(input: {}, errors: {})
|
10
|
+
super(
|
11
|
+
input: input,
|
12
|
+
errors: errors,
|
13
|
+
children: children.map { |child| child.fill(input: input, errors: errors) },
|
14
|
+
)
|
19
15
|
end
|
20
16
|
|
21
17
|
# Converts the section into an abstract syntax tree.
|
@@ -6,6 +6,14 @@ module Formalist
|
|
6
6
|
class Elements
|
7
7
|
class MultiUploadField < Field
|
8
8
|
attribute :presign_url, Types::String
|
9
|
+
attribute :presign_options, Types::Hash
|
10
|
+
attribute :render_uploaded_as, Types::String
|
11
|
+
attribute :upload_prompt, Types::String
|
12
|
+
attribute :upload_action_label, Types::String
|
13
|
+
attribute :max_file_size, Types::String
|
14
|
+
attribute :max_file_size_message, Types::String
|
15
|
+
attribute :permitted_file_type_message, Types::String
|
16
|
+
attribute :permitted_file_type_regex, Types::String
|
9
17
|
end
|
10
18
|
|
11
19
|
register :multi_upload_field, MultiUploadField
|