effective_datatables 2.6.13 → 2.6.14
Sign up to get free protection for your applications and to get access to all the features.
- 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
|