para 0.5.0 → 0.5.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 +4 -4
- data/app/assets/stylesheets/para/admin/theme/_form.sass +2 -3
- data/app/assets/stylesheets/para/admin/theme/_table.sass +4 -0
- data/app/assets/stylesheets/para/overrides/theme.sass +16 -16
- data/app/controllers/para/admin/resources_controller.rb +10 -1
- data/app/decorators/para/component/crud_decorator.rb +6 -1
- data/app/helpers/para/admin/base_helper.rb +38 -4
- data/app/helpers/para/admin/components_helper.rb +2 -2
- data/app/views/para/admin/resources/_list.html.haml +3 -0
- data/app/views/para/inputs/_nested_many.html.haml +5 -4
- data/app/views/para/inputs/nested_many/_add.html.haml +3 -0
- data/app/views/para/inputs/nested_many/_add_with_subclasses.html.haml +10 -0
- data/app/views/para/inputs/{_nested_many_container.html.haml → nested_many/_container.html.haml} +5 -1
- data/config/locales/fr.yml +18 -0
- data/lib/para/attribute_field/datetime.rb +6 -0
- data/lib/para/form_builder/containers.rb +10 -2
- data/lib/para/form_builder/nested_form.rb +4 -0
- data/lib/para/inputs/nested_many_input.rb +20 -3
- data/lib/para/plugins/routes.rb +1 -1
- data/lib/para/version.rb +1 -1
- data/lib/rails/routing_mapper.rb +2 -2
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 732caede63e764554d7a140b937d9b2c22ca9c85
|
4
|
+
data.tar.gz: 2cf5c7b7351487eb7b6c73de119fe8e0b17a79af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: abf828d53004049d831e19fb4125cc5ab54c254decc1f28a30a06bf8866f5bae76ca287d2e2b5664a28685c278106bd9ce269c51c1f6822be0984beab3a47148
|
7
|
+
data.tar.gz: c271d48d9883fd0f5268efddddf48efa61a3b77cc8ca4309896aeb8ec3c18f17f60a59522d746e04b94b34fb84c7fc1683b6147bc24fec5780015197796a88b0
|
@@ -21,7 +21,7 @@
|
|
21
21
|
display: block
|
22
22
|
&.fileinput-exists
|
23
23
|
.fileinput-placeholder
|
24
|
-
display: none
|
24
|
+
display: none
|
25
25
|
|
26
26
|
.input-group-addon
|
27
27
|
font-size: 13px
|
@@ -128,8 +128,7 @@ label.valid
|
|
128
128
|
|
129
129
|
legend
|
130
130
|
font-weight: 600
|
131
|
-
padding:
|
132
|
-
margin-top: 10px
|
131
|
+
padding: 15px 12px 15px 12px
|
133
132
|
margin-bottom: 0
|
134
133
|
width: auto
|
135
134
|
margin-left: 0
|
@@ -9,13 +9,13 @@
|
|
9
9
|
outline: none
|
10
10
|
outline-offset: 0
|
11
11
|
|
12
|
-
@mixin button-hover-focus-active($color-border, $color-bg)
|
12
|
+
@mixin button-hover-focus-active($color-border, $color-bg)
|
13
13
|
position: relative
|
14
|
-
box-shadow: 0px 2px darken($color-border, 10%)
|
14
|
+
box-shadow: 0px 2px darken($color-border, 10%)
|
15
15
|
transition: none
|
16
16
|
&:hover
|
17
17
|
top: 1px
|
18
|
-
box-shadow: 0px 1px darken($color-border, 10%)
|
18
|
+
box-shadow: 0px 1px darken($color-border, 10%)
|
19
19
|
background-color: $color-bg
|
20
20
|
border-color: $color-border
|
21
21
|
&:focus,
|
@@ -29,7 +29,7 @@
|
|
29
29
|
&:hover
|
30
30
|
background-color: darken($color-bg, 7%)
|
31
31
|
|
32
|
-
@mixin button-variant-inverse($color-border, $color-bg)
|
32
|
+
@mixin button-variant-inverse($color-border, $color-bg)
|
33
33
|
color: $color-border
|
34
34
|
background-color: transparent
|
35
35
|
box-shadow: none
|
@@ -51,8 +51,8 @@
|
|
51
51
|
background-color: darken($color-bg, 7%)
|
52
52
|
outline: none
|
53
53
|
outline: 0
|
54
|
-
|
55
|
-
.btn,
|
54
|
+
|
55
|
+
.btn,
|
56
56
|
input,
|
57
57
|
textarea,
|
58
58
|
select,
|
@@ -61,15 +61,15 @@ button
|
|
61
61
|
&,
|
62
62
|
&:active,
|
63
63
|
&.active
|
64
|
-
&:focus
|
64
|
+
&:focus
|
65
65
|
+tab-focus()
|
66
66
|
&:hover,
|
67
67
|
&:focus
|
68
68
|
+tab-focus()
|
69
|
-
|
69
|
+
|
70
70
|
|
71
71
|
.btn-default
|
72
|
-
+button-hover-focus-active($btn-default-border, $btn-default-bg)
|
72
|
+
+button-hover-focus-active($btn-default-border, $btn-default-bg)
|
73
73
|
&.btn-inverse
|
74
74
|
+button-variant-inverse($btn-default-border, $btn-default-bg)
|
75
75
|
color: $btn-default-color
|
@@ -111,25 +111,25 @@ button
|
|
111
111
|
background-color: $brand-primary
|
112
112
|
|
113
113
|
.label-success,
|
114
|
-
.badge-success
|
114
|
+
.badge-success
|
115
115
|
background-color: $brand-success
|
116
116
|
|
117
117
|
.label-info,
|
118
|
-
.badge-info
|
118
|
+
.badge-info
|
119
119
|
background-color: $brand-info
|
120
120
|
|
121
121
|
.label-warning,
|
122
|
-
.badge-warning
|
122
|
+
.badge-warning
|
123
123
|
background-color: $brand-warning
|
124
124
|
|
125
125
|
.label-danger,
|
126
|
-
.badge-danger
|
126
|
+
.badge-danger
|
127
127
|
background-color: $brand-danger
|
128
128
|
|
129
129
|
// Table
|
130
130
|
.para-component-relation-table
|
131
131
|
td > img
|
132
|
-
height: 50px
|
132
|
+
height: 50px
|
133
133
|
|
134
134
|
.pull-right.btn-group
|
135
135
|
min-width: 97px
|
@@ -148,9 +148,9 @@ button
|
|
148
148
|
clear: both
|
149
149
|
content: " "
|
150
150
|
display: table
|
151
|
-
|
151
|
+
|
152
152
|
.block.form-inputs
|
153
|
-
margin-bottom:
|
153
|
+
margin-bottom: 0
|
154
154
|
padding: 0px 10px
|
155
155
|
background-color: $body-bg
|
156
156
|
|
@@ -96,9 +96,18 @@ module Para
|
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
99
|
+
# We check for the existance of `params[:resource]` to avoid rails'
|
100
|
+
# params sanitizer to raise if no `:resource` key is found. We prefer
|
101
|
+
# to let the model handle validations instead of asking the controller
|
102
|
+
# to validate some params presence
|
103
|
+
#
|
104
|
+
# Note : This also created a bug with cancan which tried to build the
|
105
|
+
# params on a `new` action, that did not contain the `:resource`
|
106
|
+
# key in the params, which made the `#new` action form raise
|
107
|
+
#
|
99
108
|
def resource_params
|
100
109
|
@resource_params ||= parse_resource_params(
|
101
|
-
params.require(:resource).permit!
|
110
|
+
(params[:resource] && params.require(:resource).permit!) || {}
|
102
111
|
)
|
103
112
|
end
|
104
113
|
|
@@ -4,6 +4,7 @@ module Para
|
|
4
4
|
include Para::Component::BaseDecorator
|
5
5
|
|
6
6
|
def path(options = {})
|
7
|
+
options[:model] ||= model_singular_route_key
|
7
8
|
find_path([:admin, self, :resources], options)
|
8
9
|
end
|
9
10
|
|
@@ -13,7 +14,7 @@ module Para
|
|
13
14
|
end
|
14
15
|
|
15
16
|
route_key = route_key_for(options[:id], options)
|
16
|
-
options[:model] =
|
17
|
+
options[:model] = model_singular_route_key
|
17
18
|
|
18
19
|
polymorphic_path([:admin, self, route_key].compact, options)
|
19
20
|
end
|
@@ -31,6 +32,10 @@ module Para
|
|
31
32
|
:resources
|
32
33
|
end
|
33
34
|
end
|
35
|
+
|
36
|
+
def model_singular_route_key
|
37
|
+
@model_singular_route_key ||= model.model_name.singular_route_key
|
38
|
+
end
|
34
39
|
end
|
35
40
|
end
|
36
41
|
end
|
@@ -4,19 +4,39 @@ module Para
|
|
4
4
|
include Para::ApplicationHelper
|
5
5
|
|
6
6
|
def find_partial_for(relation, partial, partial_dir: 'admin/resources')
|
7
|
-
if relation.kind_of?
|
7
|
+
relation_class = if relation.kind_of?(ActiveRecord::Base)
|
8
8
|
relation = relation.class
|
9
|
+
elsif model?(relation)
|
10
|
+
relation
|
9
11
|
end
|
10
12
|
|
11
|
-
|
13
|
+
relation_name = find_relation_name_for(
|
14
|
+
'admin', plural_file_path_for(relation), partial,
|
15
|
+
relation_class: relation_class
|
16
|
+
)
|
12
17
|
|
13
|
-
if
|
14
|
-
"admin/#{
|
18
|
+
if relation_name
|
19
|
+
"admin/#{ relation_name }/#{ partial }"
|
15
20
|
else
|
16
21
|
"para/#{ partial_dir }/#{ partial }"
|
17
22
|
end
|
18
23
|
end
|
19
24
|
|
25
|
+
def find_relation_name_for(namespace, relation, partial, options = {})
|
26
|
+
return relation if partial_exists?(relation, partial)
|
27
|
+
return nil unless options[:relation_class]
|
28
|
+
|
29
|
+
relation = options[:relation_class].ancestors.find do |ancestor|
|
30
|
+
next unless model?(ancestor)
|
31
|
+
break if ancestor == ActiveRecord::Base
|
32
|
+
|
33
|
+
ancestor_name = plural_file_path_for(ancestor.name)
|
34
|
+
partial_exists?(ancestor_name, partial)
|
35
|
+
end
|
36
|
+
|
37
|
+
plural_file_path_for(relation) if relation
|
38
|
+
end
|
39
|
+
|
20
40
|
def template_path_lookup(*paths)
|
21
41
|
paths.find do |path|
|
22
42
|
lookup_context.find_all(path).any?
|
@@ -57,6 +77,20 @@ module Para
|
|
57
77
|
def flash_shared_key
|
58
78
|
'para.flash.shared'
|
59
79
|
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def plural_file_path_for(class_name)
|
84
|
+
class_name.to_s.underscore.pluralize
|
85
|
+
end
|
86
|
+
|
87
|
+
def model?(object)
|
88
|
+
object.respond_to?(:model_name)
|
89
|
+
end
|
90
|
+
|
91
|
+
def partial_exists?(relation, partial)
|
92
|
+
lookup_context.find_all("admin/#{relation}/_#{ partial }").any?
|
93
|
+
end
|
60
94
|
end
|
61
95
|
end
|
62
96
|
end
|
@@ -3,9 +3,9 @@ module Para
|
|
3
3
|
def ordered_components
|
4
4
|
@component_sections.each_with_object([]) do |section, components|
|
5
5
|
section.components.each do |component|
|
6
|
-
components << component
|
6
|
+
components << component if can?(:read, component)
|
7
7
|
end
|
8
|
-
end.sort_by(&:
|
8
|
+
end.sort_by(&:name)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
end
|
@@ -7,6 +7,9 @@
|
|
7
7
|
= render partial: find_partial_for(relation, :filters), locals: { attributes: attributes }
|
8
8
|
|
9
9
|
- if resources.length > 0
|
10
|
+
= panel.body class: 'page-entries-info' do
|
11
|
+
= page_entries_info(resources)
|
12
|
+
|
10
13
|
= panel.body class: '' do
|
11
14
|
= table_for(resources: resources, model: model, component: component, attributes: attributes)
|
12
15
|
|
@@ -1,10 +1,11 @@
|
|
1
1
|
.nested-many-field{ class: ('orderable' if orderable) }
|
2
2
|
.fields-list{ id: dom_identifier }
|
3
3
|
= form.simple_fields_for attribute_name, resources, nested_attribute_name: attribute_name, orderable: orderable do |nested_form|
|
4
|
-
= render partial: find_partial_for(model,
|
4
|
+
= render partial: find_partial_for(model, 'nested_many/container', partial_dir: 'inputs'), locals: { form: nested_form, model: model, subclass: subclass, nested_locals: nested_locals }
|
5
5
|
|
6
6
|
-# Add button
|
7
7
|
- if add_button
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
- if subclass
|
9
|
+
= render partial: 'para/inputs/nested_many/add_with_subclasses', locals: { form: form, model: model, dom_identifier: dom_identifier, nested_locals: nested_locals, attribute_name: attribute_name, orderable: orderable }
|
10
|
+
- else
|
11
|
+
= render partial: 'para/inputs/nested_many/add', locals: { form: form, model: model, dom_identifier: dom_identifier, nested_locals: nested_locals, attribute_name: attribute_name, orderable: orderable }
|
@@ -0,0 +1,3 @@
|
|
1
|
+
= link_to_add_association form, attribute_name, partial: find_partial_for(model, 'nested_many/container', partial_dir: 'inputs'), form_name: 'form', class: 'btn btn-primary', data: { :'association-insertion-node' => "##{ dom_identifier }", :'association-insertion-method' => 'append' }, render_options: { nested_attribute_name: attribute_name, orderable: orderable, locals: { model: model, nested_locals: nested_locals } } do
|
2
|
+
%i.fa.fa-plus
|
3
|
+
= t('para.form.nested.add')
|
@@ -0,0 +1,10 @@
|
|
1
|
+
.add-button.dropdown
|
2
|
+
%button.btn.btn-primary{ type: 'button', data: { toggle: 'dropdown' } }
|
3
|
+
%i.fa.fa-plus
|
4
|
+
= t('para.form.nested.add')
|
5
|
+
%span.caret
|
6
|
+
%ul.dropdown-menu
|
7
|
+
- model.descendants.sort_by { |m| m.model_name.human }.each do |submodel|
|
8
|
+
%li
|
9
|
+
= link_to_add_association form, attribute_name, wrap_object: proc { submodel.new }, partial: find_partial_for(submodel, 'nested_many/container', partial_dir: 'inputs'), form_name: 'form', class: 'dropdown-link', data: { :'association-insertion-node' => "##{ dom_identifier }", :'association-insertion-method' => 'append' }, render_options: { nested_attribute_name: attribute_name, orderable: orderable, locals: { model: submodel, nested_locals: nested_locals } } do
|
10
|
+
= submodel.model_name.human
|
data/app/views/para/inputs/{_nested_many_container.html.haml → nested_many/_container.html.haml}
RENAMED
@@ -1,3 +1,5 @@
|
|
1
|
+
- nested_locals ||= {}
|
2
|
+
|
1
3
|
.panel.panel-default.form-fields
|
2
4
|
.panel-heading
|
3
5
|
= form.reorder_anchor
|
@@ -12,6 +14,8 @@
|
|
12
14
|
.clearfix
|
13
15
|
|
14
16
|
.panel-body.form-inputs.collapse{ id: form.nested_resource_dom_id }
|
15
|
-
= render partial: find_partial_for(model, :fields), locals: { form: form }
|
17
|
+
= render partial: find_partial_for(model, :fields), locals: { form: form }.merge(nested_locals)
|
18
|
+
|
19
|
+
= form.hidden_field :type if form.object.class.column_names.include?(form.object.class.inheritance_column)
|
16
20
|
|
17
21
|
.clearfix
|
data/config/locales/fr.yml
CHANGED
@@ -114,3 +114,21 @@ fr:
|
|
114
114
|
time:
|
115
115
|
formats:
|
116
116
|
admin: '%d/%m/%Y %H:%M'
|
117
|
+
|
118
|
+
# Kaminari translations
|
119
|
+
views:
|
120
|
+
pagination:
|
121
|
+
first: "« Première"
|
122
|
+
last: "Dernière »"
|
123
|
+
previous: "‹ Précédente"
|
124
|
+
next: "Suivante ›"
|
125
|
+
truncate: "…"
|
126
|
+
helpers:
|
127
|
+
page_entries_info:
|
128
|
+
one_page:
|
129
|
+
display_entries:
|
130
|
+
zero: "Aucune entrée trouvée"
|
131
|
+
one: "Affichage des entrées <b>1 - 1</b> sur <b>1</b> au total"
|
132
|
+
other: "Affichage des entrées <b>1 - %{count}</b> sur <b>%{count}</b> au total"
|
133
|
+
more_pages:
|
134
|
+
display_entries: "Affichage des entrées <b>%{first} - %{last}</b> sur <b>%{total}</b> au total"
|
@@ -3,9 +3,15 @@ module Para
|
|
3
3
|
class DatetimeField < AttributeField::Base
|
4
4
|
register :datetime, :date, self
|
5
5
|
|
6
|
+
field_option :wrapper, :wrapper_name
|
7
|
+
|
6
8
|
def value_for(instance)
|
7
9
|
(value = instance.send(name)) && I18n.l(value)
|
8
10
|
end
|
11
|
+
|
12
|
+
def wrapper_name
|
13
|
+
:horizontal_form
|
14
|
+
end
|
9
15
|
end
|
10
16
|
end
|
11
17
|
end
|
@@ -1,9 +1,17 @@
|
|
1
1
|
module Para
|
2
2
|
module FormBuilder
|
3
3
|
module Containers
|
4
|
-
def fieldset(&block)
|
4
|
+
def fieldset(options = {}, &block)
|
5
5
|
template.content_tag(:div, class: 'block form-inputs') do
|
6
|
-
|
6
|
+
buffer = if (title = options[:title])
|
7
|
+
template.content_tag(:div, class: 'form-group') do
|
8
|
+
template.content_tag(:legend, title)
|
9
|
+
end
|
10
|
+
else
|
11
|
+
''.html_safe
|
12
|
+
end
|
13
|
+
|
14
|
+
buffer + template.capture(&block)
|
7
15
|
end
|
8
16
|
end
|
9
17
|
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module Para
|
2
2
|
module FormBuilder
|
3
3
|
module NestedForm
|
4
|
+
# FIXME : When we have a nested field that maps to an STI model, the _id
|
5
|
+
# field is passed instead of the relation, and the inverse_of
|
6
|
+
# guard doesn't work
|
7
|
+
#
|
4
8
|
def nested_fields
|
5
9
|
@nested_fields ||= fields.reject do |field|
|
6
10
|
inverse_of?(field.name)
|
@@ -4,8 +4,6 @@ module Para
|
|
4
4
|
def input(wrapper_options = nil)
|
5
5
|
input_html_options[:class] << "nested-many"
|
6
6
|
|
7
|
-
parent_model = @builder.object.class
|
8
|
-
model = parent_model.reflect_on_association(attribute_name).klass
|
9
7
|
orderable = options.fetch(:orderable, model.orderable?)
|
10
8
|
add_button = options.fetch(:add_button, true)
|
11
9
|
# Load existing resources
|
@@ -13,6 +11,8 @@ module Para
|
|
13
11
|
# Order them if the list should be orderable
|
14
12
|
resources = resources.order(:position) if orderable
|
15
13
|
|
14
|
+
locals = options.fetch(:locals, {})
|
15
|
+
|
16
16
|
template.render(
|
17
17
|
partial: 'para/inputs/nested_many',
|
18
18
|
locals: {
|
@@ -22,11 +22,21 @@ module Para
|
|
22
22
|
orderable: orderable,
|
23
23
|
add_button: add_button,
|
24
24
|
dom_identifier: dom_identifier,
|
25
|
-
resources: resources
|
25
|
+
resources: resources,
|
26
|
+
nested_locals: locals,
|
27
|
+
subclass: subclass
|
26
28
|
}
|
27
29
|
)
|
28
30
|
end
|
29
31
|
|
32
|
+
def parent_model
|
33
|
+
@parent_model ||= @builder.object.class
|
34
|
+
end
|
35
|
+
|
36
|
+
def model
|
37
|
+
@model ||= parent_model.reflect_on_association(attribute_name).klass
|
38
|
+
end
|
39
|
+
|
30
40
|
def dom_identifier
|
31
41
|
@dom_identifier ||= begin
|
32
42
|
name = attribute_name
|
@@ -35,6 +45,13 @@ module Para
|
|
35
45
|
[name, time, random].join('-')
|
36
46
|
end
|
37
47
|
end
|
48
|
+
|
49
|
+
def subclass
|
50
|
+
@subclass ||= options.fetch(
|
51
|
+
:subclass,
|
52
|
+
model.respond_to?(:descendants) && model.descendants.length > 0
|
53
|
+
)
|
54
|
+
end
|
38
55
|
end
|
39
56
|
end
|
40
57
|
end
|
data/lib/para/plugins/routes.rb
CHANGED
data/lib/para/version.rb
CHANGED
data/lib/rails/routing_mapper.rb
CHANGED
@@ -31,8 +31,8 @@ module ActionDispatch
|
|
31
31
|
controller = [component_name.to_s.singularize, 'resources'].join('_')
|
32
32
|
|
33
33
|
scope endpoint, as: as do
|
34
|
-
|
35
|
-
|
34
|
+
scope options[:scope] do
|
35
|
+
resources :resources, controller: controller do
|
36
36
|
collection do
|
37
37
|
patch :order
|
38
38
|
patch :tree
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: para
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Valentin Ballestrino
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -437,8 +437,10 @@ files:
|
|
437
437
|
- app/views/para/admin/singleton_resources/show.html.haml
|
438
438
|
- app/views/para/form/_tabs.html.haml
|
439
439
|
- app/views/para/inputs/_nested_many.html.haml
|
440
|
-
- app/views/para/inputs/_nested_many_container.html.haml
|
441
440
|
- app/views/para/inputs/_nested_one.html.haml
|
441
|
+
- app/views/para/inputs/nested_many/_add.html.haml
|
442
|
+
- app/views/para/inputs/nested_many/_add_with_subclasses.html.haml
|
443
|
+
- app/views/para/inputs/nested_many/_container.html.haml
|
442
444
|
- config/locales/en.yml
|
443
445
|
- config/locales/fr.yml
|
444
446
|
- db/migrate/20140911091225_create_para_components.rb
|