express_templates 0.4.2 → 0.5.0
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 +4 -4
- data/lib/core_extensions/string.rb +25 -0
- data/lib/express_templates/components/capabilities/resourceful.rb +135 -0
- data/lib/express_templates/components/forms/express_form.rb +2 -15
- data/lib/express_templates/components/forms/form_component.rb +2 -6
- data/lib/express_templates/components/forms/form_support.rb +13 -0
- data/lib/express_templates/components/forms/option_support.rb +19 -5
- data/lib/express_templates/components/forms/select.rb +47 -9
- data/lib/express_templates/components/forms/select_collection.rb +57 -0
- data/lib/express_templates/components/forms.rb +3 -1
- data/lib/express_templates/components/tree_for.rb +9 -5
- data/lib/express_templates/version.rb +1 -1
- data/lib/express_templates.rb +1 -0
- data/test/components/capabilities/resourceful_test.rb +63 -0
- data/test/components/forms/express_form_test.rb +9 -9
- data/test/components/forms/select_test.rb +50 -3
- data/test/core_extensions/string_test.rb +20 -0
- data/test/dummy/log/test.log +9268 -63499
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/-1ax0k6FO5drSUN6jbogg4G0JliUHLffvQUvzSePKxA.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/28LzLLDYjhr3jmu0GxjZ-ms5Bol6JilDRXpg8Zgbjqs.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5AeGDyXQbv_BTj3PD4MJpNnGVwUxLsA8H1VcwB69_wE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/B0RgtiEmqwrCQuw4AnDa3fdENtJeBtO_TqtGJuWOeNs.cache +3 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/D-tMNp19G2zWOPPhnQRUm4K8DPa8SpKPfGALkkofTeE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Pd5YOD1DAL7QtTnwETZYBCabg5DkCFgbjt4iuBOcSoY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/bSfZQxeyghTF4WIVnzGavxlg9afmSNuqcW6bA1Bm1OA.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fvD_ZNFRzd8Sc4PoTjyHPnkg4f7WMietFunnKqNjlvc.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/hKbgrf5CbMO8pe9fCHc-rI5mp1ejAhivBfvfDxBNhQA.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/kpvKX5UlhhoLJv-faeq7Ibv2KQh4ROjTiarh13gHuWI.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/lfyrNtbNtwuTXAWlmPCKTS-D3FHoPTY6h53wnUN36-A.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/lyDRhWNhfDw_YCCSbxQw_iOIV3eTfeAoX6mTREuVZSA.cache +3 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/p17lC0HAHCtk1ds_NHl9xhEyMtRjfQInw1c6fmFWguc.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/qzU7DVwQZ7z6i6pYUpssYsAj0y33GN83B4O1bLvkW_4.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/r56eI1z7iFKeySym_9zw5hVOPjb0d6IQPn5pAYTKk04.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/rGWvoeLyiyqb813IXgfDpDxks23JQoLLZOa69bzKPE8.cache +1 -0
- metadata +42 -14
- data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e3c4b0da15f9c3a8e15afd1cd406974c6a77830
|
4
|
+
data.tar.gz: 4fcaadfa00a739490b71b7a9539778aa3a7019e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ad45dd634f82597ad578c21047556a4770ad76f05b7b92e344fbbde27993dc69a7ff1d53dd3c0c116e9dadc0f444633ea6dc325cf1a7cbcb596179946bea615
|
7
|
+
data.tar.gz: 1a67f14a59f8eac2b61a840376c0ff2ab1607a2e41533c6fa1543c5caa1ce7811a3d2d0b7b4ca3a66b745d8d38e2cfd99efafbf94d78a056284b187b163ea72b
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# We use Hash#inspect in ExpressTemplates::Markup::Wrapper to reproduce arguments
|
2
|
+
# to helpers in the Rails view.
|
3
|
+
#
|
4
|
+
# Hash#inspect calls #inspect on values and keys. This allows us to
|
5
|
+
# place the resulting string into the view code with a simple substitution
|
6
|
+
# or concatenation.
|
7
|
+
#
|
8
|
+
# In special cases, however, we might want the argument or one of its keys
|
9
|
+
# or values to be the result of evaluating of a ruby expression in the view
|
10
|
+
# that does not itself return a String. The result of #inspect
|
11
|
+
# is normally a quoted and escaped string which would evaluate to a string
|
12
|
+
# in the view. What we want is a simple string of code. Here we provide
|
13
|
+
# a method that overrides #inspect in the strings eigenclass to strip off
|
14
|
+
# enclosing quotes or unwanted escapes. It shouldn't bother anybody and
|
15
|
+
# it keeps us from doing messy things elsewhere for now.
|
16
|
+
class String
|
17
|
+
def to_view_code
|
18
|
+
class << self
|
19
|
+
def inspect
|
20
|
+
super.gsub(/^"(.*)"$/,'\1')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
return self
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module ExpressTemplates
|
2
|
+
module Components
|
3
|
+
module Capabilities
|
4
|
+
|
5
|
+
module Resourceful
|
6
|
+
def namespace
|
7
|
+
@config[:namespace] || infer_namespace
|
8
|
+
end
|
9
|
+
|
10
|
+
def path_prefix
|
11
|
+
@config[:path_prefix] || infer_path_prefix
|
12
|
+
end
|
13
|
+
|
14
|
+
def resource_class
|
15
|
+
resource_class = @config[:resource_class] || _namespaced_resource_class
|
16
|
+
resource_class.constantize
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def _namespaced_resource_class
|
22
|
+
if namespace
|
23
|
+
"#{namespace}/#{resource_name}".classify
|
24
|
+
else
|
25
|
+
resource_name.classify
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def infer_namespace
|
30
|
+
expander = @args.last
|
31
|
+
if expander.try(:template)
|
32
|
+
path_parts = expander.template.virtual_path.split('/')
|
33
|
+
|
34
|
+
case
|
35
|
+
when path_parts.size == 4
|
36
|
+
path_parts.first
|
37
|
+
when path_parts.size == 3
|
38
|
+
mod = path_parts.first.classify.constantize
|
39
|
+
if mod.const_defined?(:Engine)
|
40
|
+
path_parts.first
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
else
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
else
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def infer_path_prefix
|
53
|
+
expander = @args.last
|
54
|
+
if expander.try(:template)
|
55
|
+
path_parts = expander.template.virtual_path.split('/')
|
56
|
+
|
57
|
+
case
|
58
|
+
when path_parts.size == 4
|
59
|
+
path_parts[1]
|
60
|
+
when path_parts.size == 3
|
61
|
+
mod = path_parts.first.classify.constantize
|
62
|
+
if mod.const_defined?(:Engine)
|
63
|
+
nil
|
64
|
+
else
|
65
|
+
path_parts.first
|
66
|
+
end
|
67
|
+
else
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
else
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO: this can now be inferred from the template.virtual_path
|
76
|
+
# if not supplied...
|
77
|
+
def resource_name
|
78
|
+
@config[:id].to_s.singularize
|
79
|
+
end
|
80
|
+
|
81
|
+
def collection_member_name
|
82
|
+
resource_name
|
83
|
+
end
|
84
|
+
|
85
|
+
def collection_name
|
86
|
+
collection_member_name.pluralize
|
87
|
+
end
|
88
|
+
|
89
|
+
def collection_var
|
90
|
+
"@#{collection_name}".to_sym
|
91
|
+
end
|
92
|
+
|
93
|
+
def collection
|
94
|
+
@config[:collection] || collection_var
|
95
|
+
end
|
96
|
+
|
97
|
+
def collection_path
|
98
|
+
if @config[:collection_path]
|
99
|
+
@config[:collection_path]
|
100
|
+
else
|
101
|
+
"#{collection_name_with_prefix}_path"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def collection_name_with_prefix
|
106
|
+
if path_prefix
|
107
|
+
"#{path_prefix}_#{collection_name}"
|
108
|
+
else
|
109
|
+
collection_name
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def resource_path(ivar=false)
|
114
|
+
if @config[:resource_path]
|
115
|
+
@config[:resource_path]
|
116
|
+
else
|
117
|
+
"#{resource_name_with_path_prefix}_path(#{ivar ? '@' : ''}#{resource_name})"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def resource_name_with_path_prefix
|
122
|
+
if path_prefix
|
123
|
+
"#{path_prefix}_#{resource_name}"
|
124
|
+
else
|
125
|
+
resource_name
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def attributes
|
130
|
+
resource_class.columns
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -4,6 +4,8 @@ module ExpressTemplates
|
|
4
4
|
class ExpressForm < Base
|
5
5
|
include Capabilities::Configurable
|
6
6
|
include Capabilities::Parenting
|
7
|
+
include Capabilities::Resourceful
|
8
|
+
include Forms::FormSupport
|
7
9
|
|
8
10
|
emits -> {
|
9
11
|
form( form_args ) {
|
@@ -20,16 +22,6 @@ module ExpressTemplates
|
|
20
22
|
@config[:method]
|
21
23
|
end
|
22
24
|
|
23
|
-
def form_action
|
24
|
-
if _modifying_resource?
|
25
|
-
"{{#{resource_name_for_path}_path(@#{resource_name})}}"
|
26
|
-
else # posting a new to a collection
|
27
|
-
# We also have to take in to account singular resources
|
28
|
-
# e.g. resource :config -> will throw an unknown method error of configs_path
|
29
|
-
"{{#{resource_name_for_path.pluralize}_path}}"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
25
|
|
34
26
|
def form_args
|
35
27
|
# there are no put/patch emthods in HTML5, so we have to enforce post
|
@@ -52,11 +44,6 @@ module ExpressTemplates
|
|
52
44
|
(@config[:resource_name] || @config[:id]).to_s
|
53
45
|
end
|
54
46
|
|
55
|
-
def namespace
|
56
|
-
@config[:namespace]
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
47
|
private
|
61
48
|
|
62
49
|
def _modifying_resource?
|
@@ -20,11 +20,7 @@ module ExpressTemplates
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def resource_class
|
23
|
-
|
24
|
-
"#{namespace}/#{resource_name}".classify
|
25
|
-
else
|
26
|
-
resource_name.classify
|
27
|
-
end
|
23
|
+
parent_form.resource_class
|
28
24
|
end
|
29
25
|
|
30
26
|
# Return the name attribute for the lable
|
@@ -34,7 +30,7 @@ module ExpressTemplates
|
|
34
30
|
|
35
31
|
# Return the text content for the label
|
36
32
|
def label_text
|
37
|
-
@
|
33
|
+
@config[:label] || field_name.titleize
|
38
34
|
end
|
39
35
|
|
40
36
|
# Return the field_name as a string. This taken from the first argument
|
@@ -5,12 +5,18 @@ module ExpressTemplates
|
|
5
5
|
# on the field and an means of loading the collection for supplying
|
6
6
|
# options to the user.
|
7
7
|
module OptionSupport
|
8
|
+
|
9
|
+
def has_many_through_association
|
10
|
+
reflection = resource_class.reflect_on_association(field_name.to_sym)
|
11
|
+
return reflection if reflection && reflection.macro.eql?(:has_many) && reflection.options.keys.include?(:through)
|
12
|
+
end
|
13
|
+
|
8
14
|
# Reflect on any association and return it if the association type
|
9
15
|
# is :belongs_to. Returns false if the association is not :belongs_to.
|
10
16
|
# Returns nil if there was a problem reflecting.
|
11
17
|
def belongs_to_association
|
12
18
|
# assumes the belongs_to association uses <name>_id
|
13
|
-
reflection = resource_class.
|
19
|
+
reflection = resource_class.reflect_on_association(field_name.gsub(/_id$/, '').to_sym)
|
14
20
|
if reflection && reflection.macro.eql?(:belongs_to)
|
15
21
|
return reflection
|
16
22
|
end
|
@@ -19,9 +25,13 @@ module ExpressTemplates
|
|
19
25
|
# Provide ActiveRecord code to load the associated collection as
|
20
26
|
# options for display.
|
21
27
|
def related_collection
|
22
|
-
reflection = belongs_to_association
|
28
|
+
reflection = belongs_to_association || has_many_through_association
|
23
29
|
if reflection && !reflection.polymorphic?
|
24
|
-
|
30
|
+
if cols.detect {|column| column.name.eql?('name') }
|
31
|
+
"#{reflection.klass}.all.select(:#{option_value_method}, :#{option_name_method}).order(:#{option_name_method})"
|
32
|
+
else
|
33
|
+
"#{reflection.klass}.all.sort_by(&:#{option_name_method})"
|
34
|
+
end
|
25
35
|
end
|
26
36
|
end
|
27
37
|
|
@@ -31,10 +41,14 @@ module ExpressTemplates
|
|
31
41
|
:id
|
32
42
|
end
|
33
43
|
|
44
|
+
def cols
|
45
|
+
@cols ||= (belongs_to_association||has_many_through_association).klass.columns
|
46
|
+
end
|
47
|
+
|
34
48
|
def option_name_method
|
35
|
-
cols = belongs_to_association.klass.columns
|
36
49
|
@option_name_method ||=
|
37
|
-
if cols.detect {|column| column.name.eql?('name') }
|
50
|
+
if cols.detect {|column| column.name.eql?('name') } ||
|
51
|
+
resource_class.instance_methods.include?(:name)
|
38
52
|
:name
|
39
53
|
else
|
40
54
|
if string_col = cols.detect {|column| column.type.eql?(:string) }
|
@@ -21,15 +21,26 @@ module ExpressTemplates
|
|
21
21
|
emits -> {
|
22
22
|
div(class: field_wrapper_class) {
|
23
23
|
label_tag(label_name, label_text)
|
24
|
-
select_tag(
|
24
|
+
select_tag(*select_tag_args)
|
25
25
|
}
|
26
26
|
}
|
27
27
|
|
28
|
+
def select_tag_args
|
29
|
+
args = [field_name_attribute, select_options, field_options]
|
30
|
+
args << html_options unless html_options.nil? or html_options.empty?
|
31
|
+
args
|
32
|
+
end
|
33
|
+
|
28
34
|
# Returns the options which will be supplied to the select_tag helper.
|
29
35
|
def select_options
|
30
|
-
options_specified = [Array, Hash].include?(@args.second.class) && @args.size > 2
|
36
|
+
options_specified = [Array, Hash, Proc].include?(@args.second.class) && @args.size > 2
|
31
37
|
if options_specified
|
32
|
-
|
38
|
+
if @args.second.respond_to?(:source) # can be a proc
|
39
|
+
options = "#{@args.second.source}.call()"
|
40
|
+
else
|
41
|
+
options = @args.second
|
42
|
+
end
|
43
|
+
|
33
44
|
else
|
34
45
|
options = "@#{resource_var}.class.distinct(:#{field_name}).pluck(:#{field_name})"
|
35
46
|
end
|
@@ -40,6 +51,8 @@ module ExpressTemplates
|
|
40
51
|
else
|
41
52
|
"{{options_from_collection_for_select(#{related_collection}, :id, :#{option_name_method}, @#{resource_name}.#{field_name})}}"
|
42
53
|
end
|
54
|
+
elsif has_many_through_association
|
55
|
+
"{{options_from_collection_for_select(#{related_collection}, :id, :#{option_name_method}, @#{resource_name}.#{field_name}.map(&:id))}}"
|
43
56
|
else
|
44
57
|
if selection = field_options.delete(:selected)
|
45
58
|
"{{options_for_select(#{options}, \"#{selection}\")}}"
|
@@ -49,18 +62,43 @@ module ExpressTemplates
|
|
49
62
|
end
|
50
63
|
end
|
51
64
|
|
65
|
+
def field_name_attribute
|
66
|
+
if has_many_through_association
|
67
|
+
"#{resource_name.singularize}[#{field_name.singularize}_ids]"
|
68
|
+
else
|
69
|
+
super
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
52
73
|
def field_options
|
53
74
|
# If field_otions is omitted the Expander will be
|
54
75
|
# in last or 3rd position and we don't want that
|
55
76
|
defaults = {include_blank: true}
|
56
|
-
|
57
|
-
@args[2]
|
58
|
-
else
|
59
|
-
{}
|
60
|
-
end
|
61
|
-
defaults.merge(field_options)
|
77
|
+
defaults.merge(supplied_field_options.reject {|k,v| k.eql?(:select2)})
|
62
78
|
end
|
63
79
|
|
80
|
+
def html_options
|
81
|
+
supplied_html_options
|
82
|
+
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
|
86
|
+
def supplied_field_options
|
87
|
+
if @args.size > 3 && @args[2].is_a?(Hash)
|
88
|
+
@args[2]
|
89
|
+
else
|
90
|
+
{}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def supplied_html_options
|
95
|
+
if @args.size > 4 && @args[3].is_a?(Hash)
|
96
|
+
@args[3]
|
97
|
+
else
|
98
|
+
{}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
64
102
|
end
|
65
103
|
end
|
66
104
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ExpressTemplates
|
2
|
+
module Components
|
3
|
+
module Forms
|
4
|
+
# Provides a form Select component based on the Rails *select_tag* helper.
|
5
|
+
# Parameters:
|
6
|
+
# field_name, select_options, helper_options
|
7
|
+
#
|
8
|
+
# Select options may be specified as an Array or Hash which will be
|
9
|
+
# supplied to the *options_for_select* helper.
|
10
|
+
#
|
11
|
+
class SelectCollection < Select
|
12
|
+
|
13
|
+
emits -> {
|
14
|
+
div(class: field_wrapper_class) {
|
15
|
+
label_tag(label_name, label_text)
|
16
|
+
|
17
|
+
# need this because the collection_select helper does not provide
|
18
|
+
# the hidden_field_tag trick (see rails api docs for select)
|
19
|
+
hidden_field_tag(multi_field_name, '')
|
20
|
+
|
21
|
+
collection_select(*collection_select_tag_args)
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
def collection_select_tag_args
|
26
|
+
[ resource_name,
|
27
|
+
multi_field_name,
|
28
|
+
select_options, :id, :name,
|
29
|
+
field_options,
|
30
|
+
html_options ]
|
31
|
+
end
|
32
|
+
|
33
|
+
def field_options
|
34
|
+
selected_options_ruby = "@#{resource_name}.#{multi_field_name}".to_view_code
|
35
|
+
super.merge(include_blank: false, selected: selected_options_ruby)
|
36
|
+
end
|
37
|
+
|
38
|
+
def html_options
|
39
|
+
(super||{}).merge(multiple: true)
|
40
|
+
end
|
41
|
+
|
42
|
+
def multi_field_name
|
43
|
+
if has_many_through_association
|
44
|
+
"#{field_name.singularize}_ids"
|
45
|
+
else
|
46
|
+
raise "Only use select_collection for has_many :through. #{field_name} is not has_many :through"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def select_options
|
52
|
+
"{{#{related_collection}}}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -5,11 +5,13 @@ module ExpressTemplates
|
|
5
5
|
end
|
6
6
|
end
|
7
7
|
|
8
|
+
require 'express_templates/components/forms/form_support'
|
8
9
|
require 'express_templates/components/forms/express_form'
|
9
10
|
require 'express_templates/components/forms/form_component'
|
10
11
|
require 'express_templates/components/forms/option_support'
|
11
12
|
require 'express_templates/components/forms/submit'
|
12
13
|
require 'express_templates/components/forms/select'
|
14
|
+
require 'express_templates/components/forms/select_collection'
|
13
15
|
require 'express_templates/components/forms/radio'
|
14
16
|
require 'express_templates/components/forms/checkbox'
|
15
|
-
require 'express_templates/components/forms/basic_fields'
|
17
|
+
require 'express_templates/components/forms/basic_fields'
|
@@ -11,9 +11,9 @@ module ExpressTemplates
|
|
11
11
|
# Example:
|
12
12
|
#
|
13
13
|
# ```ruby
|
14
|
-
# tree_for(:roles)
|
15
|
-
# role.name
|
16
|
-
#
|
14
|
+
# tree_for(:roles) {
|
15
|
+
# "{{role.name}}"
|
16
|
+
# }
|
17
17
|
# ```
|
18
18
|
#
|
19
19
|
# If the view has an @roles variable with a Role having children,
|
@@ -59,12 +59,16 @@ module ExpressTemplates
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def compile
|
62
|
-
collection =
|
62
|
+
collection = if @options[:collection]
|
63
|
+
"#{@options[:collection].source}.call()"
|
64
|
+
else
|
65
|
+
_variablize(@options[:id])
|
66
|
+
end
|
63
67
|
member = @options[:id].to_s.singularize
|
64
68
|
return 'ExpressTemplates::Components::TreeFor.render_in(self) {
|
65
69
|
node_renderer = '+node_renderer.gsub(/node/, member)+'
|
66
70
|
ExpressTemplates::Indenter.for(:tree) do |ws, wsnl|
|
67
|
-
"#{ws}<ul id=\"
|
71
|
+
"#{ws}<ul id=\"'+@options[:id]+'\" class=\"'+@options[:id]+' tree\">" +
|
68
72
|
'+collection+'.map do |'+member+'|
|
69
73
|
node_renderer.call('+member+', node_renderer)
|
70
74
|
end.join +
|
data/lib/express_templates.rb
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module AdminModule
|
4
|
+
module Engine
|
5
|
+
end
|
6
|
+
class SmartThing
|
7
|
+
include ExpressTemplates::Components::Capabilities::Resourceful
|
8
|
+
|
9
|
+
attr_accessor :virtual_path
|
10
|
+
|
11
|
+
def initialize(virtual_path, config = {})
|
12
|
+
@virtual_path = virtual_path
|
13
|
+
@config = config
|
14
|
+
@args = [self]
|
15
|
+
end
|
16
|
+
|
17
|
+
def template
|
18
|
+
self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Admin; end
|
24
|
+
|
25
|
+
class FooBar; end
|
26
|
+
|
27
|
+
class Something; end
|
28
|
+
|
29
|
+
module ExpressTemplates
|
30
|
+
|
31
|
+
class ResourcefulTest < ActiveSupport::TestCase
|
32
|
+
test 'infers namespace and path prefix within an engine and scope' do
|
33
|
+
smart_thing = AdminModule::SmartThing.new('admin_module/admin/something/index')
|
34
|
+
assert_equal 'admin_module', smart_thing.namespace
|
35
|
+
assert_equal 'admin', smart_thing.path_prefix
|
36
|
+
end
|
37
|
+
|
38
|
+
test 'infers a namespace and no prefix within an engine' do
|
39
|
+
# if defined? ExpressFoo::Engine
|
40
|
+
smart_thing = AdminModule::SmartThing.new('admin_module/something/index')
|
41
|
+
assert_equal 'admin_module', smart_thing.namespace
|
42
|
+
assert_equal nil, smart_thing.path_prefix
|
43
|
+
end
|
44
|
+
|
45
|
+
test 'no namespace, infers prefix within a scope within an app' do
|
46
|
+
# else of case above
|
47
|
+
smart_thing = AdminModule::SmartThing.new('admin/something/index')
|
48
|
+
assert_equal nil, smart_thing.namespace
|
49
|
+
assert_equal 'admin', smart_thing.path_prefix
|
50
|
+
end
|
51
|
+
|
52
|
+
test 'no namespace, no prefix within an app' do
|
53
|
+
smart_thing = AdminModule::SmartThing.new('somethings/index')
|
54
|
+
assert_equal nil, smart_thing.namespace
|
55
|
+
assert_equal nil, smart_thing.path_prefix
|
56
|
+
end
|
57
|
+
|
58
|
+
test "#resource_class returns resource_class option if specified" do
|
59
|
+
assert_equal FooBar, AdminModule::SmartThing.new('somethings/index', resource_class: 'FooBar').resource_class
|
60
|
+
assert_equal Something, AdminModule::SmartThing.new('somethings/index', id: :something).resource_class
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -72,16 +72,16 @@ class ExpressFormTest < ActiveSupport::TestCase
|
|
72
72
|
end
|
73
73
|
|
74
74
|
test "#form_action uses url helpers" do
|
75
|
-
assert_equal "{{foos_path}}", express_form.new(:foo).form_action
|
75
|
+
assert_equal "{{@foo.try(:persisted?) ? foo_path(@foo) : foos_path}}", express_form.new(:foo).form_action
|
76
76
|
end
|
77
77
|
|
78
78
|
test "#form_action uses correct path helper for update/patch" do
|
79
|
-
assert_equal "{{foo_path(@foo)}}", express_form.new(:foo, method: :put).form_action
|
79
|
+
assert_equal "{{@foo.try(:persisted?) ? foo_path(@foo) : foos_path}}", express_form.new(:foo, method: :put).form_action
|
80
80
|
end
|
81
81
|
|
82
82
|
test "simplest_form uses form_action for the action" do
|
83
83
|
form_open_tag = compile_simplest_form.match(/<form[^>]*>/)[0]
|
84
|
-
assert_match 'action=\"#{resources_path}\"', form_open_tag
|
84
|
+
assert_match 'action=\"#{@resource.try(:persisted?) ? resource_path(@resource) : resources_path}\"', form_open_tag
|
85
85
|
end
|
86
86
|
|
87
87
|
test "express_form default method is POST" do
|
@@ -99,10 +99,10 @@ class ExpressFormTest < ActiveSupport::TestCase
|
|
99
99
|
assert_equal 'foo', expanded_nodes.first.resource_name
|
100
100
|
end
|
101
101
|
|
102
|
-
test "express_form has a namespace option with nil default" do
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
102
|
+
# test "express_form has a namespace option with nil default" do
|
103
|
+
# form = ExpressTemplates::Components::Forms::ExpressForm
|
104
|
+
# assert_nil form.new(:person).namespace
|
105
|
+
# assert_equal 'express_engine', form.new(:person, namespace: 'express_engine').namespace
|
106
|
+
# end
|
107
107
|
|
108
|
-
end
|
108
|
+
end
|
@@ -52,16 +52,31 @@ class SelectTest < ActiveSupport::TestCase
|
|
52
52
|
[OpenStruct.new(name: 'id'), OpenStruct.new(name: 'name')]
|
53
53
|
end
|
54
54
|
end
|
55
|
+
class ::Tagging
|
56
|
+
def self.columns
|
57
|
+
[OpenStruct.new(name: 'id'), OpenStruct.new(name: 'name')]
|
58
|
+
end
|
59
|
+
end
|
55
60
|
class ::Person
|
56
61
|
def self.reflect_on_association(name)
|
57
62
|
if name.eql? :gender
|
58
|
-
|
59
|
-
class <<
|
63
|
+
dummy_belongs_to_association = Object.new
|
64
|
+
class << dummy_belongs_to_association
|
60
65
|
def macro ; :belongs_to ; end
|
61
66
|
def klass ; ::Gender ; end
|
62
67
|
def polymorphic? ; false ; end
|
63
68
|
end
|
64
|
-
return
|
69
|
+
return dummy_belongs_to_association
|
70
|
+
end
|
71
|
+
if name.eql? :taggings
|
72
|
+
dummy_has_many_through_association = Object.new
|
73
|
+
class << dummy_has_many_through_association
|
74
|
+
def macro ; :has_many ; end
|
75
|
+
def klass ; ::Tagging ; end
|
76
|
+
def options ; {:through => :peron_tags} ; end
|
77
|
+
def polymorphic? ; false ; end
|
78
|
+
end
|
79
|
+
return dummy_has_many_through_association
|
65
80
|
end
|
66
81
|
end
|
67
82
|
end
|
@@ -96,4 +111,36 @@ class SelectTest < ActiveSupport::TestCase
|
|
96
111
|
assert_no_match 'include_blank: true', ExpressTemplates.compile(&fragment)
|
97
112
|
end
|
98
113
|
|
114
|
+
test "select multiple: true if passed multiple true" do
|
115
|
+
fragment = -> {
|
116
|
+
express_form(:person) {
|
117
|
+
select :taggings, nil, include_blank: false, multiple: true
|
118
|
+
}
|
119
|
+
}
|
120
|
+
assert_match 'multiple: true', ExpressTemplates.compile(&fragment)
|
121
|
+
end
|
122
|
+
|
123
|
+
test "select multiple gets options from associated has_many_through collection" do
|
124
|
+
fragment = -> {
|
125
|
+
express_form(:person) {
|
126
|
+
select :taggings, nil, include_blank: false, multiple: true
|
127
|
+
}
|
128
|
+
}
|
129
|
+
assert_match 'tagging_ids', ExpressTemplates.compile(&fragment)
|
130
|
+
assert_match 'options_from_collection_for_select(Tagging.all.select(:id, :name).order(:name), :id, :name, @person.taggings.map(&:id))',
|
131
|
+
ExpressTemplates.compile(&fragment)
|
132
|
+
end
|
133
|
+
|
134
|
+
test "select_collection uses collection_select" do
|
135
|
+
fragment = -> {
|
136
|
+
express_form(:person) {
|
137
|
+
select_collection :taggings
|
138
|
+
}
|
139
|
+
}
|
140
|
+
assert_match 'tagging_ids', ExpressTemplates.compile(&fragment)
|
141
|
+
assert_match 'collection_select("person", "tagging_ids", Tagging.all.select(:id, :name).order(:name), :id, :name, {:include_blank=>false, :selected=>@person.tagging_ids}, multiple: true)',
|
142
|
+
ExpressTemplates.compile(&fragment)
|
143
|
+
end
|
144
|
+
|
145
|
+
|
99
146
|
end
|