effective_datatables 2.6.13 → 2.6.14
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/helpers/effective_datatables_helper.rb +84 -111
- data/app/helpers/effective_datatables_private_helper.rb +106 -0
- data/app/models/effective/effective_datatable/dsl/datatable.rb +7 -2
- data/app/models/effective/effective_datatable/rendering.rb +128 -22
- data/app/views/effective/datatables/_actions_column.html.haml +12 -24
- data/lib/effective_datatables/engine.rb +1 -0
- data/lib/effective_datatables/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e74b48943a26fed6030dccee8555337684bc4c49
|
|
4
|
+
data.tar.gz: ef20573e54accb0e2135e66a6c9f77a8720c51af
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 01980cdb85274c5cf73a7131bbbe8ef9b1873930eb61a03b23bcec45b62e97f4c79bd3e59c9fa298306da752de323127cf556670fe351de2e69f77f33c516ff7
|
|
7
|
+
data.tar.gz: b163136bc40e04ec0cc698b9ff20c58e97402573071ee47a67513d710140fbb00e031e5388b9c34a1140af4a232d3751fccb3823aa239406551b43f3614f078b
|
|
@@ -1,13 +1,40 @@
|
|
|
1
|
+
# These are expected to be called by a developer. They are part of the datatables DSL.
|
|
1
2
|
module EffectiveDatatablesHelper
|
|
3
|
+
|
|
2
4
|
def render_datatable(datatable, input_js_options = nil)
|
|
3
|
-
|
|
5
|
+
raise 'expected datatable to be present' unless datatable
|
|
6
|
+
|
|
4
7
|
datatable.view ||= self
|
|
5
8
|
|
|
9
|
+
begin
|
|
10
|
+
EffectiveDatatables.authorized?(controller, :index, datatable.try(:collection_class) || datatable.try(:class)) || raise('unauthorized')
|
|
11
|
+
rescue => e
|
|
12
|
+
return content_tag(:p, "You are not authorized to view this datatable. (cannot :index, #{datatable.try(:collection_class) || datatable.try(:class)})")
|
|
13
|
+
end
|
|
14
|
+
|
|
6
15
|
render partial: 'effective/datatables/datatable',
|
|
7
16
|
locals: { datatable: datatable, input_js_options: input_js_options.try(:to_json) }
|
|
8
17
|
end
|
|
9
18
|
|
|
19
|
+
def render_simple_datatable(datatable, input_js_options = nil)
|
|
20
|
+
raise 'expected datatable to be present' unless datatable
|
|
21
|
+
|
|
22
|
+
datatable.view ||= self
|
|
23
|
+
datatable.simple = true
|
|
24
|
+
|
|
25
|
+
begin
|
|
26
|
+
EffectiveDatatables.authorized?(controller, :index, datatable.try(:collection_class) || datatable.try(:class)) || raise('unauthorized')
|
|
27
|
+
rescue => e
|
|
28
|
+
return content_tag(:p, "You are not authorized to view this datatable. (cannot :index, #{datatable.try(:collection_class) || datatable.try(:class)})")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
render partial: 'effective/datatables/datatable',
|
|
32
|
+
locals: {datatable: datatable, input_js_options: input_js_options.try(:to_json) }
|
|
33
|
+
end
|
|
34
|
+
|
|
10
35
|
def render_datatable_scopes(datatable)
|
|
36
|
+
raise 'expected datatable to be present' unless datatable
|
|
37
|
+
|
|
11
38
|
return unless datatable.scopes.present?
|
|
12
39
|
datatable.view ||= self
|
|
13
40
|
|
|
@@ -15,6 +42,8 @@ module EffectiveDatatablesHelper
|
|
|
15
42
|
end
|
|
16
43
|
|
|
17
44
|
def render_datatable_charts(datatable)
|
|
45
|
+
raise 'expected datatable to be present' unless datatable
|
|
46
|
+
|
|
18
47
|
return unless datatable.charts.present?
|
|
19
48
|
datatable.view ||= self
|
|
20
49
|
|
|
@@ -22,6 +51,8 @@ module EffectiveDatatablesHelper
|
|
|
22
51
|
end
|
|
23
52
|
|
|
24
53
|
def render_datatable_chart(datatable, name)
|
|
54
|
+
raise 'expected datatable to be present' unless datatable
|
|
55
|
+
|
|
25
56
|
return unless datatable.charts.present?
|
|
26
57
|
return unless datatable.charts[name].present?
|
|
27
58
|
datatable.view ||= self
|
|
@@ -40,116 +71,6 @@ module EffectiveDatatablesHelper
|
|
|
40
71
|
locals: { datatable: datatable, chart: chart }
|
|
41
72
|
end
|
|
42
73
|
|
|
43
|
-
def render_simple_datatable(datatable, input_js_options = nil)
|
|
44
|
-
return if datatable.nil?
|
|
45
|
-
datatable.view ||= self
|
|
46
|
-
datatable.simple = true
|
|
47
|
-
|
|
48
|
-
render partial: 'effective/datatables/datatable',
|
|
49
|
-
locals: {datatable: datatable, input_js_options: input_js_options.try(:to_json) }
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def datatable_default_order(datatable)
|
|
53
|
-
[datatable.order_index, datatable.order_direction.downcase].to_json()
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# https://datatables.net/reference/option/columns
|
|
57
|
-
def datatable_columns(datatable)
|
|
58
|
-
form = nil
|
|
59
|
-
simple_form_for(:datatable_filter, url: '#', html: {id: "#{datatable.to_param}-form"}) { |f| form = f }
|
|
60
|
-
|
|
61
|
-
datatable.table_columns.map do |name, options|
|
|
62
|
-
{
|
|
63
|
-
name: options[:name],
|
|
64
|
-
title: content_tag(:span, options[:label], class: 'filter-label'),
|
|
65
|
-
className: options[:class],
|
|
66
|
-
width: options[:width],
|
|
67
|
-
responsivePriority: (options[:responsivePriority] || 10000), # 10,000 is datatables default
|
|
68
|
-
sortable: (options[:sortable] && !datatable.simple?),
|
|
69
|
-
visible: (options[:visible].respond_to?(:call) ? datatable.instance_exec(&options[:visible]) : options[:visible]),
|
|
70
|
-
filterHtml: (datatable_header_filter(form, name, datatable.search_terms[name], options) unless datatable.simple?),
|
|
71
|
-
filterSelectedValue: options[:filter][:selected]
|
|
72
|
-
}
|
|
73
|
-
end.to_json()
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
def datatable_bulk_actions(datatable)
|
|
77
|
-
bulk_actions_column = datatable.table_columns.find { |_, options| options[:bulk_actions_column] }.try(:second)
|
|
78
|
-
return false unless bulk_actions_column
|
|
79
|
-
|
|
80
|
-
{
|
|
81
|
-
dropdownHtml: render(
|
|
82
|
-
partial: bulk_actions_column[:dropdown_partial],
|
|
83
|
-
locals: { datatable: datatable, dropdown_block: bulk_actions_column[:dropdown_block] }.merge(bulk_actions_column[:partial_locals])
|
|
84
|
-
)
|
|
85
|
-
}.to_json()
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def datatable_header_filter(form, name, value, opts)
|
|
89
|
-
return render(partial: opts[:header_partial], locals: {form: form, name: (opts[:label] || name), column: opts}) if opts[:header_partial].present?
|
|
90
|
-
|
|
91
|
-
include_blank = opts[:filter].key?(:include_blank) ? opts[:filter][:include_blank] : (opts[:label] || name.titleize)
|
|
92
|
-
pattern = opts[:filter].key?(:pattern) ? opts[:filter][:pattern] : nil
|
|
93
|
-
placeholder = opts[:filter].key?(:placeholder) ? opts[:filter][:placeholder] : (opts[:label] || name.titleize)
|
|
94
|
-
title = opts[:filter].key?(:title) ? opts[:filter][:title] : (opts[:label] || name.titleize)
|
|
95
|
-
|
|
96
|
-
case opts[:filter][:as]
|
|
97
|
-
when :string, :text, :number
|
|
98
|
-
form.input name, label: false, required: false, value: value,
|
|
99
|
-
as: :string,
|
|
100
|
-
placeholder: placeholder,
|
|
101
|
-
input_html: { name: nil, value: value, title: title, pattern: pattern, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} }
|
|
102
|
-
when :obfuscated_id
|
|
103
|
-
pattern ||= "[0-9]{3}-?[0-9]{4}-?[0-9]{3}"
|
|
104
|
-
title = opts[:filter].key?(:title) ? opts[:filter][:title] : "Expected format: XXX-XXXX-XXX"
|
|
105
|
-
|
|
106
|
-
form.input name, label: false, required: false, value: value,
|
|
107
|
-
as: :string,
|
|
108
|
-
placeholder: placeholder,
|
|
109
|
-
input_html: { name: nil, value: value, title: title, pattern: pattern, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} }
|
|
110
|
-
when :date
|
|
111
|
-
form.input name, label: false, required: false, value: value,
|
|
112
|
-
as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_date_picker) ? :effective_date_picker : :string),
|
|
113
|
-
placeholder: placeholder,
|
|
114
|
-
input_group: false,
|
|
115
|
-
input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
|
|
116
|
-
input_js: { useStrict: true, keepInvalid: true }
|
|
117
|
-
when :datetime
|
|
118
|
-
form.input name, label: false, required: false, value: value,
|
|
119
|
-
as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_date_time_picker) ? :effective_date_time_picker : :string),
|
|
120
|
-
placeholder: placeholder,
|
|
121
|
-
input_group: false,
|
|
122
|
-
input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
|
|
123
|
-
input_js: { useStrict: true, keepInvalid: true } # Keep invalid format like "2015-11" so we can still filter by year, month or day
|
|
124
|
-
when :select, :boolean
|
|
125
|
-
form.input name, label: false, required: false, value: value,
|
|
126
|
-
as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_select) ? :effective_select : :select),
|
|
127
|
-
collection: opts[:filter][:collection],
|
|
128
|
-
selected: opts[:filter][:selected],
|
|
129
|
-
multiple: opts[:filter][:multiple] == true,
|
|
130
|
-
include_blank: include_blank,
|
|
131
|
-
input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
|
|
132
|
-
input_js: { placeholder: placeholder }
|
|
133
|
-
when :grouped_select
|
|
134
|
-
form.input name, label: false, required: false, value: value,
|
|
135
|
-
as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_select) ? :effective_select : :grouped_select),
|
|
136
|
-
collection: opts[:filter][:collection],
|
|
137
|
-
selected: opts[:filter][:selected],
|
|
138
|
-
multiple: opts[:filter][:multiple] == true,
|
|
139
|
-
include_blank: include_blank,
|
|
140
|
-
grouped: true,
|
|
141
|
-
polymorphic: opts[:filter][:polymorphic] == true,
|
|
142
|
-
group_label_method: opts[:filter][:group_label_method] || :first,
|
|
143
|
-
group_method: opts[:filter][:group_method] || :last,
|
|
144
|
-
input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
|
|
145
|
-
input_js: { placeholder: placeholder }
|
|
146
|
-
when :bulk_actions_column
|
|
147
|
-
form.input name, label: false, required: false, value: nil,
|
|
148
|
-
as: :boolean,
|
|
149
|
-
input_html: { name: nil, value: nil, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index], 'role' => 'bulk-actions-all'} }
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
|
|
153
74
|
def datatables_admin_path?
|
|
154
75
|
@datatables_admin_path ||= (
|
|
155
76
|
path = request.path.to_s.downcase.chomp('/') + '/'
|
|
@@ -163,4 +84,56 @@ module EffectiveDatatablesHelper
|
|
|
163
84
|
attributes[:active_admin_path] rescue false
|
|
164
85
|
end
|
|
165
86
|
|
|
87
|
+
### Icon Helpers for actions_column or elsewhere
|
|
88
|
+
def show_icon_to(path, options = {})
|
|
89
|
+
glyphicon_to('eye-open', path, {title: 'Show'}.merge(options))
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def edit_icon_to(path, options = {})
|
|
93
|
+
glyphicon_to('edit', path, {title: 'Edit'}.merge(options))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def destroy_icon_to(path, options = {})
|
|
97
|
+
defaults = {title: 'Destroy', data: {method: :delete, confirm: 'Delete this item?'}}
|
|
98
|
+
glyphicon_to('trash', path, defaults.merge(options))
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def archive_icon_to(path, options = {})
|
|
102
|
+
defaults = {title: 'Archive', data: {method: :delete, confirm: 'Archive this item?'}}
|
|
103
|
+
glyphicon_to('trash', path, defaults.merge(options))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def unarchive_icon_to(path, options = {})
|
|
107
|
+
defaults = {title: 'Unarchive', data: {confirm: 'Unarchive this item?'}}
|
|
108
|
+
glyphicon_to('retweet', path, defaults.merge(options))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def settings_icon_to(path, options = {})
|
|
112
|
+
glyphicon_to('cog', path, {title: 'Settings'}.merge(options))
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def ok_icon_to(path, options = {})
|
|
116
|
+
glyphicon_to('ok', path, {title: 'OK'}.merge(options))
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def approve_icon_to(path, options = {})
|
|
120
|
+
glyphicon_to('ok', path, {title: 'Approve'}.merge(options))
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def remove_icon_to(path, options = {})
|
|
124
|
+
glyphicon_to('remove', path, {title: 'Remove'}.merge(options))
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def glyphicon_to(icon, path, options = {})
|
|
128
|
+
content_tag(:a, options.merge(href: path)) do
|
|
129
|
+
if icon.start_with?('glyphicon-')
|
|
130
|
+
content_tag(:span, '', class: "glyphicon #{icon}")
|
|
131
|
+
else
|
|
132
|
+
content_tag(:span, '', class: "glyphicon glyphicon-#{icon}")
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
alias_method :bootstrap_icon_to, :glyphicon_to
|
|
137
|
+
alias_method :glyph_icon_to, :glyphicon_to
|
|
138
|
+
|
|
166
139
|
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# These aren't expected to be called by a developer.
|
|
2
|
+
# They are internal datatables methods, but you could still call them on the view.
|
|
3
|
+
module EffectiveDatatablesPrivateHelper
|
|
4
|
+
|
|
5
|
+
def datatable_default_order(datatable)
|
|
6
|
+
[datatable.order_index, datatable.order_direction.downcase].to_json()
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# https://datatables.net/reference/option/columns
|
|
10
|
+
def datatable_columns(datatable)
|
|
11
|
+
form = nil
|
|
12
|
+
simple_form_for(:datatable_filter, url: '#', html: {id: "#{datatable.to_param}-form"}) { |f| form = f }
|
|
13
|
+
|
|
14
|
+
datatable.table_columns.map do |name, options|
|
|
15
|
+
{
|
|
16
|
+
name: options[:name],
|
|
17
|
+
title: content_tag(:span, options[:label], class: 'filter-label'),
|
|
18
|
+
className: options[:class],
|
|
19
|
+
width: options[:width],
|
|
20
|
+
responsivePriority: (options[:responsivePriority] || 10000), # 10,000 is datatables default
|
|
21
|
+
sortable: (options[:sortable] && !datatable.simple?),
|
|
22
|
+
visible: (options[:visible].respond_to?(:call) ? datatable.instance_exec(&options[:visible]) : options[:visible]),
|
|
23
|
+
filterHtml: (datatable_header_filter(form, name, datatable.search_terms[name], options) unless datatable.simple?),
|
|
24
|
+
filterSelectedValue: options[:filter][:selected]
|
|
25
|
+
}
|
|
26
|
+
end.to_json()
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def datatable_bulk_actions(datatable)
|
|
30
|
+
bulk_actions_column = datatable.table_columns.find { |_, options| options[:bulk_actions_column] }.try(:second)
|
|
31
|
+
return false unless bulk_actions_column
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
dropdownHtml: render(
|
|
35
|
+
partial: bulk_actions_column[:dropdown_partial],
|
|
36
|
+
locals: { datatable: datatable, dropdown_block: bulk_actions_column[:dropdown_block] }.merge(bulk_actions_column[:partial_locals])
|
|
37
|
+
)
|
|
38
|
+
}.to_json()
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def datatable_header_filter(form, name, value, opts)
|
|
42
|
+
return render(partial: opts[:header_partial], locals: {form: form, name: (opts[:label] || name), column: opts}) if opts[:header_partial].present?
|
|
43
|
+
|
|
44
|
+
include_blank = opts[:filter].key?(:include_blank) ? opts[:filter][:include_blank] : (opts[:label] || name.titleize)
|
|
45
|
+
pattern = opts[:filter].key?(:pattern) ? opts[:filter][:pattern] : nil
|
|
46
|
+
placeholder = opts[:filter].key?(:placeholder) ? opts[:filter][:placeholder] : (opts[:label] || name.titleize)
|
|
47
|
+
title = opts[:filter].key?(:title) ? opts[:filter][:title] : (opts[:label] || name.titleize)
|
|
48
|
+
|
|
49
|
+
case opts[:filter][:as]
|
|
50
|
+
when :string, :text, :number
|
|
51
|
+
form.input name, label: false, required: false, value: value,
|
|
52
|
+
as: :string,
|
|
53
|
+
placeholder: placeholder,
|
|
54
|
+
input_html: { name: nil, value: value, title: title, pattern: pattern, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} }
|
|
55
|
+
when :obfuscated_id
|
|
56
|
+
pattern ||= '[0-9]{3}-?[0-9]{4}-?[0-9]{3}'
|
|
57
|
+
title = opts[:filter].key?(:title) ? opts[:filter][:title] : 'Expected format: XXX-XXXX-XXX'
|
|
58
|
+
|
|
59
|
+
form.input name, label: false, required: false, value: value,
|
|
60
|
+
as: :string,
|
|
61
|
+
placeholder: placeholder,
|
|
62
|
+
input_html: { name: nil, value: value, title: title, pattern: pattern, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} }
|
|
63
|
+
when :date
|
|
64
|
+
form.input name, label: false, required: false, value: value,
|
|
65
|
+
as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_date_picker) ? :effective_date_picker : :string),
|
|
66
|
+
placeholder: placeholder,
|
|
67
|
+
input_group: false,
|
|
68
|
+
input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
|
|
69
|
+
input_js: { useStrict: true, keepInvalid: true }
|
|
70
|
+
when :datetime
|
|
71
|
+
form.input name, label: false, required: false, value: value,
|
|
72
|
+
as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_date_time_picker) ? :effective_date_time_picker : :string),
|
|
73
|
+
placeholder: placeholder,
|
|
74
|
+
input_group: false,
|
|
75
|
+
input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
|
|
76
|
+
input_js: { useStrict: true, keepInvalid: true } # Keep invalid format like "2015-11" so we can still filter by year, month or day
|
|
77
|
+
when :select, :boolean
|
|
78
|
+
form.input name, label: false, required: false, value: value,
|
|
79
|
+
as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_select) ? :effective_select : :select),
|
|
80
|
+
collection: opts[:filter][:collection],
|
|
81
|
+
selected: opts[:filter][:selected],
|
|
82
|
+
multiple: opts[:filter][:multiple] == true,
|
|
83
|
+
include_blank: include_blank,
|
|
84
|
+
input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
|
|
85
|
+
input_js: { placeholder: placeholder }
|
|
86
|
+
when :grouped_select
|
|
87
|
+
form.input name, label: false, required: false, value: value,
|
|
88
|
+
as: (ActionView::Helpers::FormBuilder.instance_methods.include?(:effective_select) ? :effective_select : :grouped_select),
|
|
89
|
+
collection: opts[:filter][:collection],
|
|
90
|
+
selected: opts[:filter][:selected],
|
|
91
|
+
multiple: opts[:filter][:multiple] == true,
|
|
92
|
+
include_blank: include_blank,
|
|
93
|
+
grouped: true,
|
|
94
|
+
polymorphic: opts[:filter][:polymorphic] == true,
|
|
95
|
+
group_label_method: opts[:filter][:group_label_method] || :first,
|
|
96
|
+
group_method: opts[:filter][:group_method] || :last,
|
|
97
|
+
input_html: { name: nil, value: value, title: title, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index]} },
|
|
98
|
+
input_js: { placeholder: placeholder }
|
|
99
|
+
when :bulk_actions_column
|
|
100
|
+
form.input name, label: false, required: false, value: nil,
|
|
101
|
+
as: :boolean,
|
|
102
|
+
input_html: { name: nil, value: nil, autocomplete: 'off', data: {'column-name' => opts[:name], 'column-index' => opts[:index], 'role' => 'bulk-actions-all'} }
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
@@ -13,7 +13,7 @@ module Effective
|
|
|
13
13
|
|
|
14
14
|
def table_column(name, options = {}, proc = nil, &block)
|
|
15
15
|
if block_given?
|
|
16
|
-
raise "You cannot use partial: ... with the block syntax" if options[:partial]
|
|
16
|
+
raise "You cannot use partial: ... with the block syntax" if options[:partial] && !options[:type] == :actions
|
|
17
17
|
raise "You cannot use proc: ... with the block syntax" if options[:proc]
|
|
18
18
|
options[:block] = block
|
|
19
19
|
end
|
|
@@ -27,6 +27,8 @@ module Effective
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def actions_column(options = {}, proc = nil, &block)
|
|
30
|
+
raise 'first parameter to actions_column should be a hash' unless options.kind_of?(Hash)
|
|
31
|
+
|
|
30
32
|
show = options.fetch(:show, (EffectiveDatatables.actions_column[:show] rescue false))
|
|
31
33
|
edit = options.fetch(:edit, (EffectiveDatatables.actions_column[:edit] rescue false))
|
|
32
34
|
destroy = options.fetch(:destroy, (EffectiveDatatables.actions_column[:destroy] rescue false))
|
|
@@ -34,6 +36,7 @@ module Effective
|
|
|
34
36
|
name = options.fetch(:name, 'actions')
|
|
35
37
|
|
|
36
38
|
opts = {
|
|
39
|
+
type: :actions,
|
|
37
40
|
sortable: false,
|
|
38
41
|
filter: false,
|
|
39
42
|
responsivePriority: 0,
|
|
@@ -41,12 +44,14 @@ module Effective
|
|
|
41
44
|
}.merge(options)
|
|
42
45
|
|
|
43
46
|
opts[:partial_local] ||= :resource unless opts[:partial].present?
|
|
44
|
-
opts[:partial] ||= '/effective/datatables/actions_column' unless
|
|
47
|
+
opts[:partial] ||= '/effective/datatables/actions_column' unless proc.present?
|
|
45
48
|
|
|
46
49
|
table_column(name, opts, proc, &block)
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
def bulk_actions_column(options = {}, proc = nil, &block)
|
|
53
|
+
raise 'first parameter to bulk_actions_column should be a hash' unless options.kind_of?(Hash)
|
|
54
|
+
|
|
50
55
|
name = options.fetch(:name, 'bulk_actions')
|
|
51
56
|
resource_method = options.fetch(:resource_method, :to_param)
|
|
52
57
|
|
|
@@ -65,25 +65,7 @@ module Effective
|
|
|
65
65
|
|
|
66
66
|
locals.merge!(opts[:partial_locals]) if opts[:partial_locals]
|
|
67
67
|
|
|
68
|
-
if
|
|
69
|
-
if locals[:show_action] == :authorize
|
|
70
|
-
locals[:show_action] = (EffectiveDatatables.authorized?(controller, :show, collection_class) rescue false)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
if locals[:edit_action] == :authorize
|
|
74
|
-
locals[:edit_action] = (EffectiveDatatables.authorized?(controller, :edit, collection_class) rescue false)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
if locals[:destroy_action] == :authorize
|
|
78
|
-
locals[:destroy_action] = (EffectiveDatatables.authorized?(controller, :destroy, collection_class) rescue false)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
if locals[:unarchive_action] == :authorize
|
|
82
|
-
locals[:unarchive_action] = (EffectiveDatatables.authorized?(controller, :unarchive, collection_class) rescue false)
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# If locals[:show_action] == :authorize_each, this will get run again.
|
|
68
|
+
add_actions_column_locals(locals) if opts[:type] == :actions
|
|
87
69
|
|
|
88
70
|
rendered[name] = (render(
|
|
89
71
|
:partial => opts[:partial],
|
|
@@ -101,12 +83,20 @@ module Effective
|
|
|
101
83
|
begin
|
|
102
84
|
if opts[:visible] == false
|
|
103
85
|
BLANK
|
|
104
|
-
elsif opts[:partial]
|
|
105
|
-
rendered[name][index]
|
|
106
86
|
elsif opts[:block]
|
|
107
|
-
|
|
87
|
+
begin
|
|
88
|
+
view.instance_exec(obj, collection, self, &opts[:block])
|
|
89
|
+
rescue NoMethodError => e
|
|
90
|
+
if opts[:type] == :actions && e.message == 'super called outside of method'
|
|
91
|
+
rendered[name][index]
|
|
92
|
+
else
|
|
93
|
+
raise(e)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
108
96
|
elsif opts[:proc]
|
|
109
97
|
view.instance_exec(obj, collection, self, &opts[:proc])
|
|
98
|
+
elsif opts[:partial]
|
|
99
|
+
rendered[name][index]
|
|
110
100
|
elsif opts[:type] == :belongs_to
|
|
111
101
|
(obj.send(name) rescue nil).to_s
|
|
112
102
|
elsif opts[:type] == :belongs_to_polymorphic
|
|
@@ -224,6 +214,122 @@ module Effective
|
|
|
224
214
|
end
|
|
225
215
|
end
|
|
226
216
|
|
|
217
|
+
protected
|
|
218
|
+
|
|
219
|
+
def add_actions_column_locals(locals)
|
|
220
|
+
return unless active_record_collection?
|
|
221
|
+
|
|
222
|
+
# Consider authorization levels first
|
|
223
|
+
|
|
224
|
+
if locals[:show_action] == :authorize
|
|
225
|
+
locals[:show_action] = (EffectiveDatatables.authorized?(controller, :show, collection_class) rescue false)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
if locals[:edit_action] == :authorize
|
|
229
|
+
locals[:edit_action] = (EffectiveDatatables.authorized?(controller, :edit, collection_class) rescue false)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
if locals[:destroy_action] == :authorize
|
|
233
|
+
locals[:destroy_action] = (EffectiveDatatables.authorized?(controller, :destroy, collection_class) rescue false)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
if locals[:unarchive_action] == :authorize
|
|
237
|
+
locals[:unarchive_action] = (EffectiveDatatables.authorized?(controller, :unarchive, collection_class) rescue false)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Then we look at the routes to see if these actions _actually_ exist
|
|
241
|
+
|
|
242
|
+
routes = Rails.application.routes
|
|
243
|
+
|
|
244
|
+
begin
|
|
245
|
+
resource = collection_class.new(id: 123)
|
|
246
|
+
resource.define_singleton_method(:persisted?) { true } # We override persisted? to get the correct action urls
|
|
247
|
+
rescue => e
|
|
248
|
+
return
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
if (locals[:show_action] == true || locals[:show_action] == :authorize_each) && !locals[:show_path]
|
|
252
|
+
# Try our namespace
|
|
253
|
+
url = (view.polymorphic_path([*controller_namespace, resource]) rescue false)
|
|
254
|
+
url = false if url && !(routes.recognize_path(url) rescue false)
|
|
255
|
+
|
|
256
|
+
# Try no namespace
|
|
257
|
+
unless url
|
|
258
|
+
url = (view.polymorphic_path(resource) rescue false)
|
|
259
|
+
url = false if url && !(routes.recognize_path(url) rescue false)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# So if we have a URL, this is an action we can link to
|
|
263
|
+
if url
|
|
264
|
+
locals[:show_path] = url.gsub('123', ':to_param')
|
|
265
|
+
else
|
|
266
|
+
locals[:show_action] = false
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
if (locals[:edit_action] == true || locals[:edit_action] == :authorize_each) && !locals[:edit_path]
|
|
271
|
+
# Try our namespace
|
|
272
|
+
url = (view.edit_polymorphic_path([*controller_namespace, resource]) rescue false)
|
|
273
|
+
url = false if url && !(routes.recognize_path(url) rescue false)
|
|
274
|
+
|
|
275
|
+
# Try no namespace
|
|
276
|
+
unless url
|
|
277
|
+
url = (view.edit_polymorphic_path(resource) rescue false)
|
|
278
|
+
url = false if url && !(routes.recognize_path(url) rescue false)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# So if we have a URL, this is an action we can link to
|
|
282
|
+
if url
|
|
283
|
+
locals[:edit_path] = url.gsub('123', ':to_param')
|
|
284
|
+
else
|
|
285
|
+
locals[:edit_action] = false
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
if (locals[:destroy_action] == true || locals[:destroy_action] == :authorize_each) && !locals[:destroy_path]
|
|
290
|
+
# Try our namespace
|
|
291
|
+
url = (view.polymorphic_path([*controller_namespace, resource]) rescue false)
|
|
292
|
+
url = false if url && !(routes.recognize_path(url, method: :delete) rescue false)
|
|
293
|
+
|
|
294
|
+
# Try no namespace
|
|
295
|
+
unless url
|
|
296
|
+
url = (view.polymorphic_path(resource) rescue false)
|
|
297
|
+
url = false if url && !(routes.recognize_path(url, method: :delete) rescue false)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# So if we have a URL, this is an action we can link to
|
|
301
|
+
if url
|
|
302
|
+
locals[:destroy_path] = url.gsub('123', ':to_param')
|
|
303
|
+
else
|
|
304
|
+
locals[:destroy_action] = false
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
if resource.respond_to?(:archived?)
|
|
309
|
+
if (locals[:unarchive_action] == true || locals[:unarchive_action] == :authorize_each) && !locals[:unarchive_path]
|
|
310
|
+
# Try our namespace
|
|
311
|
+
url = (view.polymorphic_path([*controller_namespace, resource], action: :unarchive) rescue false)
|
|
312
|
+
url = false if url && !(routes.recognize_path(url) rescue false)
|
|
313
|
+
|
|
314
|
+
# Try no namespace
|
|
315
|
+
unless url
|
|
316
|
+
url = (view.polymorphic_path(resource, action: :unarchive) rescue false)
|
|
317
|
+
url = false if url && !(routes.recognize_path(url) rescue false)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
# So if we have a URL, this is an action we can link to
|
|
321
|
+
if url
|
|
322
|
+
locals[:unarchive_path] = url.gsub('123', ':to_param')
|
|
323
|
+
else
|
|
324
|
+
locals[:unarchive_action] = false
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
else
|
|
328
|
+
locals[:unarchive_action] = false
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
end
|
|
332
|
+
|
|
227
333
|
private
|
|
228
334
|
|
|
229
335
|
def controller_namespace
|
|
@@ -23,30 +23,18 @@
|
|
|
23
23
|
unarchive_action = instance_exec(resource, &unarchive_action)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
- if show_action
|
|
27
|
-
|
|
28
|
-
- if url.present?
|
|
29
|
-
%a{href: url, title: 'Show'}
|
|
30
|
-
%span.glyphicon.glyphicon-eye-open
|
|
26
|
+
- if show_action && show_path
|
|
27
|
+
= show_icon_to show_path.gsub(':to_param', resource.to_param)
|
|
31
28
|
|
|
32
|
-
- if edit_action
|
|
33
|
-
|
|
34
|
-
- if url.present?
|
|
35
|
-
%a{href: url, title: 'Edit'}
|
|
36
|
-
%span.glyphicon.glyphicon-edit
|
|
29
|
+
- if edit_action && edit_path
|
|
30
|
+
= edit_icon_to edit_path.gsub(':to_param', resource.to_param)
|
|
37
31
|
|
|
38
|
-
- if destroy_action
|
|
39
|
-
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
%span.glyphicon.glyphicon-trash
|
|
44
|
-
- elsif resource.respond_to?(:archived?) == false
|
|
45
|
-
%a{href: url, title: 'Delete', data: {method: :delete, confirm: "Are you sure you want to delete this item?"}}
|
|
46
|
-
%span.glyphicon.glyphicon-trash
|
|
32
|
+
- if destroy_action && destroy_path
|
|
33
|
+
- if resource.respond_to?(:archived?) && !resource.archived?
|
|
34
|
+
= archive_icon_to destroy_path.gsub(':to_param', resource.to_param)
|
|
35
|
+
- elsif resource.respond_to?(:archived?) == false
|
|
36
|
+
= destroy_icon_to destroy_path.gsub(':to_param', resource.to_param)
|
|
47
37
|
|
|
48
|
-
- if unarchive_action &&
|
|
49
|
-
-
|
|
50
|
-
|
|
51
|
-
%a{href: url, title: 'Unarchive', data: {confirm: 'Are you sure you want to unarchive this item?'}}
|
|
52
|
-
%span.glyphicon.glyphicon-retweet
|
|
38
|
+
- if unarchive_action && unarchive_path
|
|
39
|
+
- if resource.respond_to?(:archived?) && resource.archived?
|
|
40
|
+
= unarchive_icon_to unarchive_path.gsub(':to_param', resource.to_param)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: effective_datatables
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.6.
|
|
4
|
+
version: 2.6.14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Code and Effect
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2016-
|
|
11
|
+
date: 2016-10-03 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -135,6 +135,7 @@ files:
|
|
|
135
135
|
- app/assets/stylesheets/effective_datatables/_overrides.scss.erb
|
|
136
136
|
- app/controllers/effective/datatables_controller.rb
|
|
137
137
|
- app/helpers/effective_datatables_helper.rb
|
|
138
|
+
- app/helpers/effective_datatables_private_helper.rb
|
|
138
139
|
- app/models/effective/access_denied.rb
|
|
139
140
|
- app/models/effective/active_record_datatable_tool.rb
|
|
140
141
|
- app/models/effective/array_datatable_tool.rb
|