data_grid 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +3 -0
- data/CHANGELOG +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/Rakefile +1 -0
- data/app/assets/images/data_grid/calendar_view_month.png +0 -0
- data/app/assets/images/data_grid/csv.gif +0 -0
- data/app/assets/images/data_grid/delete.png +0 -0
- data/app/assets/images/data_grid/edit.png +0 -0
- data/app/assets/images/data_grid/no.png +0 -0
- data/app/assets/images/data_grid/sort_down.gif +0 -0
- data/app/assets/images/data_grid/sort_up.gif +0 -0
- data/app/assets/images/data_grid/yes.png +0 -0
- data/app/assets/javascripts/data_grid/data_grid.js +24 -0
- data/app/assets/javascripts/data_grid/grid_calendar/calendar-setup.js +200 -0
- data/app/assets/javascripts/data_grid/grid_calendar/calendar-setup_stripped.js +21 -0
- data/app/assets/javascripts/data_grid/grid_calendar/calendar.js +1819 -0
- data/app/assets/javascripts/data_grid/grid_calendar/calendar_original.js +1845 -0
- data/app/assets/javascripts/data_grid/grid_calendar/calendar_patched.js +1819 -0
- data/app/assets/javascripts/data_grid/grid_calendar/calendar_stripped.js +14 -0
- data/app/assets/javascripts/data_grid/grid_calendar/img.gif +0 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-af.js +39 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-al.js +101 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-bg.js +124 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-big5-utf8.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-big5.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-br.js +108 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-ca.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-cs-utf8.js +65 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-cs-win.js +65 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-da.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-de.js +124 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-du.js +45 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-el.js +89 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-en.js +127 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-es.js +129 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-fi.js +98 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-fr.js +125 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-he-utf8.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-hr-utf8.js +49 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-hr.js +0 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-hu.js +124 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-it.js +124 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-jp.js +45 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-ko-utf8.js +120 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-ko.js +120 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-lt-utf8.js +114 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-lt.js +114 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-lv.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-nl.js +73 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-no.js +114 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-pl-utf8.js +93 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-pl.js +56 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-pt.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-ro.js +66 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-ru.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-ru_win_.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-si.js +94 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-sk.js +99 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-sp.js +110 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-sv.js +93 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-tr.js +58 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/calendar-zh.js +119 -0
- data/app/assets/javascripts/data_grid/grid_calendar/lang/cn_utf8.js +123 -0
- data/app/assets/javascripts/data_grid/grid_calendar/menuarrow.gif +0 -0
- data/app/assets/javascripts/data_grid/grid_calendar/menuarrow2.gif +0 -0
- data/app/assets/stylesheets/data_grid/data_grid.css +90 -0
- data/app/assets/stylesheets/data_grid/data_grid_3_0.css +90 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-blue.css +233 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-blue2.css +237 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-brown.css +226 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-green.css +230 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-system.css +252 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-tas.css +240 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-win2k-1.css +272 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-win2k-2.css +272 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-win2k-cold-1.css +266 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/calendar-win2k-cold-2.css +272 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/img.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/menuarrow.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/menuarrow2.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/active-bg.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/dark-bg.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/hover-bg.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/menuarrow.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/normal-bg.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/rowhover-bg.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/status-bg.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/theme.css +236 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/title-bg.gif +0 -0
- data/app/assets/stylesheets/data_grid/grid_calendar/skins/aqua/today-bg.gif +0 -0
- data/app/views/data_grid/_data_grid.html.erb +101 -0
- data/config/locales/en.yml +10 -0
- data/data_grid.gemspec +27 -0
- data/lib/data_grid/column.rb +38 -0
- data/lib/data_grid/controller.rb +30 -0
- data/lib/data_grid/cookies_state_saver.rb +42 -0
- data/lib/data_grid/csv_exporter.rb +79 -0
- data/lib/data_grid/data_grid_logic.rb +175 -0
- data/lib/data_grid/data_source_array.rb +267 -0
- data/lib/data_grid/data_source_orm.rb +207 -0
- data/lib/data_grid/engine.rb +19 -0
- data/lib/data_grid/summaries.rb +34 -0
- data/lib/data_grid/version.rb +3 -0
- data/lib/data_grid/view_helpers.rb +271 -0
- data/lib/data_grid.rb +43 -0
- data/lib/generators/data_grid/copy_view_generator.rb +16 -0
- data/lib/generators/data_grid/install_generator.rb +29 -0
- data/lib/generators/templates/data_grid.rb +29 -0
- data/lib/generators/templates/stylesheets/data_grid/data_grid_3_0.css +90 -0
- data/spec/orm_spec.rb +57 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/active_record.rb +17 -0
- metadata +118 -5
@@ -0,0 +1,175 @@
|
|
1
|
+
module DataGrid
|
2
|
+
class DataGridLogic
|
3
|
+
|
4
|
+
attr_accessor :per_page, :page, :name, :columns, :in_data, :out_data, :data_class, :params, :sort, :sort_direction, :view_context, :pages, :total, :export_enabled, :summaries, :row_styles, :state_saver, :show_footer, :hidden_row, :out_hidden_rows, :initial_sort, :global_summaries, :count_statement, :extra_orm_options, :export_filename
|
5
|
+
|
6
|
+
|
7
|
+
# Initialize
|
8
|
+
def initialize(attrs = {})
|
9
|
+
# Internal copy od request params
|
10
|
+
self.params = attrs[:params].except(:action).except(:controller).except(:utf8)
|
11
|
+
|
12
|
+
# Display rows per page
|
13
|
+
self.per_page = (attrs[:per_page] || DataGrid.per_page).to_i
|
14
|
+
|
15
|
+
# Current page
|
16
|
+
self.page = (attrs[:page] || 1).to_i
|
17
|
+
self.page = 1 if self.page <= 0
|
18
|
+
self.page = 1 if self.page >= 10000000
|
19
|
+
|
20
|
+
# DataGrid name. Has to be set if two or more grids on page.
|
21
|
+
self.name = attrs[:name] || ''
|
22
|
+
|
23
|
+
# Sort by this field
|
24
|
+
self.sort = attrs[:sort]
|
25
|
+
|
26
|
+
# Sort direction - (asc, desc)
|
27
|
+
self.sort_direction = attrs[:sort] || DataGrid.sort_direction
|
28
|
+
|
29
|
+
# Internal array of columns
|
30
|
+
self.columns = attrs[:columns] || []
|
31
|
+
|
32
|
+
# Internal representation of prepared data to display
|
33
|
+
self.out_data = []
|
34
|
+
|
35
|
+
# Name of state saver method - (cookies)
|
36
|
+
self.state_saver = attrs[:state_saver]
|
37
|
+
|
38
|
+
# Show grid footer?
|
39
|
+
self.show_footer = attrs[:show_footer] || DataGrid.show_footer
|
40
|
+
|
41
|
+
# Internal representation of hidden rows - row below each row
|
42
|
+
self.hidden_row = attrs[:hidden_row]
|
43
|
+
|
44
|
+
# Internal representation of prepared hidden rows
|
45
|
+
self.out_hidden_rows = []
|
46
|
+
|
47
|
+
# Initial data grid sorting (ie. 'age ASC')
|
48
|
+
self.initial_sort = attrs[:initial_sort]
|
49
|
+
|
50
|
+
# SQL which counts rows
|
51
|
+
self.count_statement = attrs[:count_statement] || nil
|
52
|
+
|
53
|
+
# Extra where statement
|
54
|
+
self.extra_orm_options = attrs[:extra_orm_options] || nil
|
55
|
+
|
56
|
+
# Name of exported filename
|
57
|
+
self.export_filename = attrs[:export_filename] || DataGrid.export_filename
|
58
|
+
|
59
|
+
# Name of export method - (csv)
|
60
|
+
self.export_enabled = attrs[:export_enabled]
|
61
|
+
end
|
62
|
+
|
63
|
+
# Add new column
|
64
|
+
def add_column(column_field, column_attrs = {})
|
65
|
+
self.columns << Column.new(column_field, column_attrs)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Assign data
|
69
|
+
def data(_data)
|
70
|
+
self.in_data = _data
|
71
|
+
self.data_class = _data
|
72
|
+
self.data_class = _data.class
|
73
|
+
self.data_class = _data if _data.class != Array
|
74
|
+
end
|
75
|
+
|
76
|
+
# Sorting comes from URL?
|
77
|
+
def sorting?
|
78
|
+
!self.sort.nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
# Any column has filters?
|
82
|
+
def filters?
|
83
|
+
!self.columns.select{|c| !c.filter.nil?}.empty?
|
84
|
+
end
|
85
|
+
|
86
|
+
# Any column has summary?
|
87
|
+
def summary?
|
88
|
+
!self.columns.select{|c| !c.summary.nil?}.empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
# Any column has global summary?
|
92
|
+
def global_summary?
|
93
|
+
!self.columns.select{|c| !c.global_summary.nil?}.empty?
|
94
|
+
end
|
95
|
+
|
96
|
+
# Display footer?
|
97
|
+
def footer?
|
98
|
+
self.show_footer
|
99
|
+
end
|
100
|
+
|
101
|
+
# Get params from request
|
102
|
+
def get_params_from_request
|
103
|
+
self.per_page = (params["per_page_#{self.name}"] || self.per_page).to_i
|
104
|
+
self.page = (params["page_#{self.name}"] || self.page).to_i
|
105
|
+
self.sort = params["sort_#{self.name}"] ? params["sort_#{self.name}"].split('_').pop.to_i : self.sort
|
106
|
+
self.sort_direction = params["sort_direction_#{self.name}"] || self.sort_direction
|
107
|
+
|
108
|
+
self.columns.each_with_index do |col, col_index|
|
109
|
+
col.filter_value = params["filter_#{self.name}_#{col_index}"]
|
110
|
+
if params["filter_#{self.name}_#{col_index}_from"] or params["filter_#{self.name}_#{col_index}_to"]
|
111
|
+
col.filter_value = params["filter_#{self.name}_#{col_index}_from"].to_s + DataGrid.range_separator +
|
112
|
+
params["filter_#{self.name}_#{col_index}_to"].to_s
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Used in view to show entries from
|
118
|
+
def entries_from
|
119
|
+
ef = (self.page-1)*self.per_page
|
120
|
+
ef.zero? ? 1 : ef
|
121
|
+
end
|
122
|
+
|
123
|
+
# Used in view to show entries to
|
124
|
+
def entries_to
|
125
|
+
if (self.page)*self.per_page > total
|
126
|
+
total
|
127
|
+
else
|
128
|
+
(self.page)*self.per_page
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Assign data
|
133
|
+
def data(_data)
|
134
|
+
self.in_data = _data
|
135
|
+
self.data_class = _data
|
136
|
+
self.data_class = _data.class
|
137
|
+
self.data_class = _data if _data.class != Array
|
138
|
+
end
|
139
|
+
|
140
|
+
alias :data= :data
|
141
|
+
|
142
|
+
|
143
|
+
# Prepare data, do sorting, filtering, paging
|
144
|
+
def prepare_data
|
145
|
+
data_source = nil
|
146
|
+
if self.data_class == Array
|
147
|
+
require 'data_grid/data_source_array'
|
148
|
+
data_source = DataGrid::DataSourceArray.new
|
149
|
+
else
|
150
|
+
require 'data_grid/data_source_orm'
|
151
|
+
data_source = DataGrid::DataSourceORM.new
|
152
|
+
end
|
153
|
+
|
154
|
+
data_source.data_grid = self
|
155
|
+
data_source.prepare_data
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
# Row styler is a column, which is hidden and describes style of the row
|
160
|
+
def row_styler
|
161
|
+
styler_column = self.columns.select{|col| col.title == :row_styler}
|
162
|
+
|
163
|
+
if styler_column and !styler_column.empty?
|
164
|
+
styler_column_index = self.columns.index(styler_column.first)
|
165
|
+
|
166
|
+
self.row_styles = []
|
167
|
+
self.out_data.each do |row|
|
168
|
+
self.row_styles << row[styler_column_index]
|
169
|
+
end
|
170
|
+
|
171
|
+
self.columns.delete_at(styler_column_index)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,267 @@
|
|
1
|
+
# Source od grid data comes from Array
|
2
|
+
|
3
|
+
module DataGrid
|
4
|
+
class DataSourceArray
|
5
|
+
|
6
|
+
attr_accessor :data_grid
|
7
|
+
|
8
|
+
# Main function which prepares data
|
9
|
+
def prepare_data
|
10
|
+
initial_data_eval
|
11
|
+
initial_sorting if self.data_grid.sorting?
|
12
|
+
filter
|
13
|
+
global_summary_array
|
14
|
+
pagination
|
15
|
+
summary_array
|
16
|
+
self.data_grid.row_styler
|
17
|
+
prepare_data_for_filters
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def direction_as_int
|
24
|
+
if self.data_grid.sort_direction == 'ASC'
|
25
|
+
return 1
|
26
|
+
else
|
27
|
+
return -1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Eval lambdas
|
32
|
+
def initial_data_eval
|
33
|
+
self.data_grid.in_data.each_with_index do |row, row_index|
|
34
|
+
entry = []
|
35
|
+
|
36
|
+
self.data_grid.columns.each_with_index do |col, index|
|
37
|
+
# Eval if sorting or filtering by or summary column
|
38
|
+
if (self.data_grid.sort == index) or (col.filter and !col.filter_value.blank?) or col.global_summary or col.summary
|
39
|
+
if col.sort_by.class == Symbol
|
40
|
+
if col.sort_by != col.field
|
41
|
+
if col.field.class == Symbol
|
42
|
+
to_entry = [row.send(col.field), row.send(col.sort_by)]
|
43
|
+
else
|
44
|
+
to_entry = [col.field.call(row, self.data_grid.view_context), row.send(col.sort_by)]
|
45
|
+
end
|
46
|
+
else
|
47
|
+
to_entry = row.send(col.sort_by)
|
48
|
+
end
|
49
|
+
else
|
50
|
+
# Call lambda
|
51
|
+
to_entry = col.field.call(row, self.data_grid.view_context)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
# Other column are not evaluated, for now has only row index
|
55
|
+
to_entry = row_index
|
56
|
+
end
|
57
|
+
|
58
|
+
to_entry = 0 if to_entry.nil?
|
59
|
+
entry << to_entry
|
60
|
+
end
|
61
|
+
|
62
|
+
self.data_grid.out_data << entry
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Initial sorting
|
67
|
+
def initial_sorting
|
68
|
+
self.data_grid.out_data.sort! do |a, b|
|
69
|
+
a_v = a[self.data_grid.sort]
|
70
|
+
b_v = b[self.data_grid.sort]
|
71
|
+
|
72
|
+
a_v = a_v[1] if a_v.class == Array
|
73
|
+
b_v = b_v[1] if b_v.class == Array
|
74
|
+
|
75
|
+
a_v = a_v.upcase if a_v.class == String
|
76
|
+
b_v = b_v.upcase if b_v.class == String
|
77
|
+
if (a_v > b_v)
|
78
|
+
direction_as_int
|
79
|
+
else
|
80
|
+
if a_v == b_v
|
81
|
+
0
|
82
|
+
else
|
83
|
+
direction_as_int * -1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Filter
|
90
|
+
def filter
|
91
|
+
if self.data_grid.filters?
|
92
|
+
date_format = I18n.t(:"date.formats.default", {:locale => I18n.locale })
|
93
|
+
filtered_data = []
|
94
|
+
self.data_grid.out_data.each do |row|
|
95
|
+
add_row = true
|
96
|
+
self.data_grid.columns.each_with_index do |col, col_index|
|
97
|
+
if col.filter and !col.filter_value.blank?
|
98
|
+
case col.filter
|
99
|
+
when :auto
|
100
|
+
add_row = false if row[col_index] != col.filter_value
|
101
|
+
when :text
|
102
|
+
add_row = false if row[col_index] !~ Regexp.new(col.filter_value, true) and row[col_index].first !~ Regexp.new(col.filter_value, true)
|
103
|
+
when :number
|
104
|
+
add_row = false if row[col_index].to_f != col.filter_value.to_f
|
105
|
+
when :range
|
106
|
+
range = col.filter_value.split(DataGrid.range_separator)
|
107
|
+
|
108
|
+
if !range[0].blank? and !range[1].blank?
|
109
|
+
begin
|
110
|
+
range[0] < 2
|
111
|
+
rescue
|
112
|
+
range[0] = range[0].to_f
|
113
|
+
range[1] = range[1].to_f
|
114
|
+
end
|
115
|
+
add_row = false if row[col_index] < range[0] or row[col_index] > range[1]
|
116
|
+
elsif range[0].blank? and !range[1].blank?
|
117
|
+
begin
|
118
|
+
range[1] < 2
|
119
|
+
rescue
|
120
|
+
range[1] = range[1].to_f
|
121
|
+
end
|
122
|
+
add_row = false if row[col_index] > range[1]
|
123
|
+
elsif range[1].blank? and !range[0].blank?
|
124
|
+
begin
|
125
|
+
range[0] < 2
|
126
|
+
rescue
|
127
|
+
range[0] = range[0].to_f
|
128
|
+
end
|
129
|
+
add_row = false if row[col_index] < range[0]
|
130
|
+
end
|
131
|
+
|
132
|
+
when :date
|
133
|
+
range = col.filter_value.split(DataGrid.range_separator)
|
134
|
+
|
135
|
+
if !range[0].blank? and !range[1].blank?
|
136
|
+
begin
|
137
|
+
range[0] < 2
|
138
|
+
rescue
|
139
|
+
range[0] = DateTime.strptime(range[0], date_format)
|
140
|
+
range[1] = DateTime.strptime(range[1], date_format)
|
141
|
+
end
|
142
|
+
add_row = false if row[col_index].class == Fixnum or row[col_index] < range[0] or row[col_index] > range[1]
|
143
|
+
elsif range[0].blank? and !range[1].blank?
|
144
|
+
begin
|
145
|
+
range[1] < 2
|
146
|
+
rescue
|
147
|
+
range[1] = DateTime.strptime(range[1], date_format)
|
148
|
+
end
|
149
|
+
add_row = false if row[col_index].class == Fixnum or row[col_index] > range[1]
|
150
|
+
elsif range[1].blank? and !range[0].blank?
|
151
|
+
begin
|
152
|
+
range[0] < 2
|
153
|
+
rescue
|
154
|
+
range[0] = DateTime.strptime(range[0], date_format)
|
155
|
+
end
|
156
|
+
add_row = false if row[col_index].class == Fixnum or row[col_index] < range[0]
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
filtered_data << row if add_row
|
163
|
+
end
|
164
|
+
|
165
|
+
self.data_grid.out_data = filtered_data
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
# Pagination
|
171
|
+
def pagination
|
172
|
+
self.data_grid.total = self.data_grid.out_data.size
|
173
|
+
self.data_grid.pages = self.data_grid.out_data.size/self.data_grid.per_page
|
174
|
+
self.data_grid.pages = (self.data_grid.pages != self.data_grid.pages.ceil) ? self.data_grid.pages.ceil + 1 : self.data_grid.pages.ceil
|
175
|
+
|
176
|
+
page = self.data_grid.page
|
177
|
+
per_page = self.data_grid.per_page
|
178
|
+
|
179
|
+
offset = (page - 1) * per_page
|
180
|
+
if !paged_out_data = self.data_grid.out_data[offset..(offset + per_page - 1)]
|
181
|
+
paged_out_data = self.data_grid.out_data[0..(per_page - 1)]
|
182
|
+
end
|
183
|
+
|
184
|
+
self.data_grid.out_data = []
|
185
|
+
paged_out_data.each_with_index do |row, row_index|
|
186
|
+
entry = []
|
187
|
+
|
188
|
+
self.data_grid.columns.each_with_index { |col, index|
|
189
|
+
# If colum is sorted/filtered/summary
|
190
|
+
if (self.data_grid.sort != index) and (!col.filter or col.filter_value.blank?) and !col.summary and !col.global_summary
|
191
|
+
field = row[index]
|
192
|
+
if col.field.class == Symbol
|
193
|
+
if col.field == :auto
|
194
|
+
entry << row_index + 1 + (page-1)*per_page
|
195
|
+
else
|
196
|
+
entry << self.data_grid.in_data[field].send(col.field)
|
197
|
+
end
|
198
|
+
else
|
199
|
+
entry << col.field.call(self.data_grid.in_data[field], self.data_grid.view_context)
|
200
|
+
end
|
201
|
+
else
|
202
|
+
entry << row[index]
|
203
|
+
end
|
204
|
+
}
|
205
|
+
|
206
|
+
self.data_grid.out_data << entry
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# Prepare data for filters
|
211
|
+
def prepare_data_for_filters
|
212
|
+
self.data_grid.columns.each do |col|
|
213
|
+
next if col.filter.nil? # if no filter
|
214
|
+
|
215
|
+
# Prepare auto filters
|
216
|
+
if col.filter == :auto
|
217
|
+
self.data_grid.in_data.each do |d|
|
218
|
+
if col.sort_by.class == Symbol
|
219
|
+
col.filter_data << d.send(col.sort_by)
|
220
|
+
else
|
221
|
+
# Call lambda
|
222
|
+
col.filter_data << col.field.call(d, self.data_grid)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
col.filter_data.uniq!
|
227
|
+
col.filter_data.sort!
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Summary
|
233
|
+
def summary_array
|
234
|
+
if self.data_grid.summary?
|
235
|
+
self.data_grid.summaries = []
|
236
|
+
self.data_grid.columns.each_with_index do |col, col_index|
|
237
|
+
if col.summary
|
238
|
+
column_data = []
|
239
|
+
self.data_grid.out_data.each do |row|
|
240
|
+
column_data << row[col_index]
|
241
|
+
end
|
242
|
+
|
243
|
+
self.data_grid.summaries[col_index] = DataGrid::Summaries.send(col.summary, column_data)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Global Summary
|
250
|
+
def global_summary_array
|
251
|
+
if self.data_grid.summary?
|
252
|
+
self.data_grid.global_summaries = []
|
253
|
+
self.data_grid.columns.each_with_index do |col, col_index|
|
254
|
+
if col.global_summary
|
255
|
+
column_data = []
|
256
|
+
self.data_grid.out_data.each do |row|
|
257
|
+
column_data << row[col_index]
|
258
|
+
end
|
259
|
+
|
260
|
+
self.data_grid.global_summaries[col_index] = DataGrid::Summaries.send(col.global_summary, column_data)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
@@ -0,0 +1,207 @@
|
|
1
|
+
# Source od grid data comes from ORM
|
2
|
+
|
3
|
+
module DataGrid
|
4
|
+
class DataSourceORM
|
5
|
+
|
6
|
+
attr_accessor :data_grid
|
7
|
+
|
8
|
+
def prepare_data
|
9
|
+
global_summary_orm
|
10
|
+
get_data_from_orm
|
11
|
+
summary_orm
|
12
|
+
self.data_grid.row_styler
|
13
|
+
prepare_orm_data_for_filters
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def direction_as_int
|
20
|
+
if self.sort_direction == 'ASC'
|
21
|
+
return 1
|
22
|
+
else
|
23
|
+
return -1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Filter data using ORM
|
28
|
+
def prepare_orm_filters
|
29
|
+
filters = [[]]
|
30
|
+
date_format = I18n.t(:"date.formats.default", {:locale => I18n.locale })
|
31
|
+
self.data_grid.columns.each_with_index do |col, col_index|
|
32
|
+
if col.filter and !col.filter_value.blank?
|
33
|
+
case col.filter
|
34
|
+
when :boolean
|
35
|
+
filters[0] << "#{col.filter_by} = ?"
|
36
|
+
filters << (col.filter_value == '1') ? true : false
|
37
|
+
when :auto
|
38
|
+
filters[0] << "#{col.filter_by} = ?"
|
39
|
+
filters << col.filter_value
|
40
|
+
when :text
|
41
|
+
filters[0] << "#{col.filter_by} #{ActiveRecord::Base.connection.adapter_name.downcase.to_sym == :postgresql ? 'ILIKE' : 'LIKE'} ?"
|
42
|
+
filters << "%#{col.filter_value}%"
|
43
|
+
when :number
|
44
|
+
filters[0] << "#{col.filter_by} = ?"
|
45
|
+
filters << col.filter_value.to_i
|
46
|
+
when :range
|
47
|
+
range = col.filter_value.split(DataGrid.range_separator)
|
48
|
+
|
49
|
+
if !range[0].blank? and !range[1].blank?
|
50
|
+
begin
|
51
|
+
range[0] < 2
|
52
|
+
rescue
|
53
|
+
range[0] = range[0].to_f
|
54
|
+
range[1] = range[1].to_f
|
55
|
+
end
|
56
|
+
filters[0] << "#{col.filter_by} >= ? AND #{col.filter_by} <= ?"
|
57
|
+
filters << range[0]
|
58
|
+
filters << range[1]
|
59
|
+
elsif range[0].blank? and !range[1].blank?
|
60
|
+
begin
|
61
|
+
range[1] < 2
|
62
|
+
rescue
|
63
|
+
range[1] = range[1].to_f
|
64
|
+
end
|
65
|
+
filters[0] << "#{col.filter_by} <= ?"
|
66
|
+
filters << range[1]
|
67
|
+
elsif range[1].blank? and !range[0].blank?
|
68
|
+
begin
|
69
|
+
range[0] < 2
|
70
|
+
rescue
|
71
|
+
range[0] = range[0].to_f
|
72
|
+
end
|
73
|
+
filters[0] << "#{col.filter_by} >= ?"
|
74
|
+
filters << range[0]
|
75
|
+
end
|
76
|
+
|
77
|
+
when :date
|
78
|
+
range = col.filter_value.split(DataGrid.range_separator)
|
79
|
+
|
80
|
+
if !range[0].blank? and !range[1].blank?
|
81
|
+
begin
|
82
|
+
range[0] < 2
|
83
|
+
rescue
|
84
|
+
range[0] = DateTime.strptime(range[0], date_format)
|
85
|
+
range[1] = DateTime.strptime(range[1], date_format)
|
86
|
+
end
|
87
|
+
filters[0] << "#{col.filter_by} >= ? AND #{col.filter_by} <= ?"
|
88
|
+
filters << range[0]
|
89
|
+
filters << range[1]
|
90
|
+
elsif range[0].blank? and !range[1].blank?
|
91
|
+
begin
|
92
|
+
range[1] < 2
|
93
|
+
rescue
|
94
|
+
range[1] = DateTime.strptime(range[1], date_format)
|
95
|
+
end
|
96
|
+
filters[0] << "#{col.filter_by} <= ?"
|
97
|
+
filters << range[1]
|
98
|
+
elsif range[1].blank? and !range[0].blank?
|
99
|
+
begin
|
100
|
+
range[0] < 2
|
101
|
+
rescue
|
102
|
+
range[0] = DateTime.strptime(range[0], date_format)
|
103
|
+
end
|
104
|
+
filters[0] << "#{col.filter_by} >= ?"
|
105
|
+
filters << range[0]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
filters[0] = filters[0].join(' AND ')
|
112
|
+
filters
|
113
|
+
end
|
114
|
+
|
115
|
+
# Get data
|
116
|
+
def get_data_from_orm
|
117
|
+
self.data_grid.out_data = []
|
118
|
+
|
119
|
+
# prepare filters as ActiveRecord conditions
|
120
|
+
filters = prepare_orm_filters
|
121
|
+
self.data_grid.total = self.data_grid.in_data.where(filters).where(self.data_grid.extra_orm_options).count(self.data_grid.count_statement)
|
122
|
+
self.data_grid.page = 1 if ((self.data_grid.per_page * (self.data_grid.page - 1)) > self.data_grid.total)
|
123
|
+
offset = (self.data_grid.page - 1) * self.data_grid.per_page
|
124
|
+
|
125
|
+
|
126
|
+
# get data sorted
|
127
|
+
if self.data_grid.sorting?
|
128
|
+
self.data_grid.in_data = self.data_grid.in_data.limit(self.data_grid.per_page.to_i).offset(offset.to_i).order("#{self.data_grid.columns[self.data_grid.sort].sort_field} #{self.data_grid.sort_direction}" + (self.data_grid.initial_sort.blank? ? '' : ", #{self.data_grid.initial_sort}")).where(filters).where(self.data_grid.extra_orm_options)
|
129
|
+
else
|
130
|
+
self.data_grid.in_data = self.data_grid.in_data.limit(self.data_grid.per_page.to_i).offset(offset.to_i).where(filters).order(self.data_grid.initial_sort.blank? ? '' : "#{self.data_grid.initial_sort}").where(self.data_grid.extra_orm_options)
|
131
|
+
end
|
132
|
+
|
133
|
+
# prepare out data array, eval lambdas
|
134
|
+
self.data_grid.in_data.each_with_index do |obj, row_index|
|
135
|
+
row = []
|
136
|
+
self.data_grid.columns.each do |col|
|
137
|
+
if col.field.class == Symbol
|
138
|
+
if col.field == :auto
|
139
|
+
row << row_index + 1 + (self.data_grid.page-1)*self.data_grid.per_page
|
140
|
+
else
|
141
|
+
row << obj.send(col.field)
|
142
|
+
end
|
143
|
+
else
|
144
|
+
row << col.field.call(obj, self.data_grid.view_context)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Hidden rows
|
149
|
+
unless self.data_grid.hidden_row.nil?
|
150
|
+
self.data_grid.out_hidden_rows << obj.send(self.data_grid.hidden_row)
|
151
|
+
end
|
152
|
+
|
153
|
+
self.data_grid.out_data << row
|
154
|
+
end
|
155
|
+
|
156
|
+
self.data_grid.pages = (self.data_grid.total/self.data_grid.per_page.to_f).ceil
|
157
|
+
end
|
158
|
+
|
159
|
+
# Prepare data for filters
|
160
|
+
def prepare_orm_data_for_filters
|
161
|
+
self.data_grid.columns.each do |col|
|
162
|
+
next if col.filter.nil? # if no filter
|
163
|
+
|
164
|
+
# Prepare auto filters
|
165
|
+
if col.filter == :auto
|
166
|
+
col.filter_data = self.data_grid.data_class.select("DISTINCT (#{col.filter_by}) as fc").to_a.to_a.map(&:fc)
|
167
|
+
end
|
168
|
+
|
169
|
+
col.filter_data.uniq!
|
170
|
+
col.filter_data.sort!
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Summary
|
175
|
+
def summary_orm
|
176
|
+
if self.data_grid.summary?
|
177
|
+
self.data_grid.summaries = []
|
178
|
+
self.data_grid.columns.each_with_index do |col, col_index|
|
179
|
+
if col.summary
|
180
|
+
column_data = []
|
181
|
+
self.data_grid.out_data.each do |row|
|
182
|
+
column_data << row[col_index]
|
183
|
+
end
|
184
|
+
|
185
|
+
self.data_grid.summaries[col_index] = DataGrid::Summaries.send(col.summary, column_data)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Global Summary
|
192
|
+
def global_summary_orm
|
193
|
+
if self.data_grid.global_summary?
|
194
|
+
# prepare filters as ActiveRecord conditions
|
195
|
+
filters = prepare_orm_filters
|
196
|
+
|
197
|
+
self.data_grid.global_summaries = []
|
198
|
+
self.data_grid.columns.each_with_index do |col, col_index|
|
199
|
+
if col.global_summary
|
200
|
+
self.data_grid.global_summaries[col_index] = self.data_grid.in_data.scoped(:conditions => filters).where(self.data_grid.extra_orm_options).send(*col.global_summary)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DataGrid
|
2
|
+
class Engine < Rails::Engine
|
3
|
+
|
4
|
+
initializer "data_grid.action_controller" do
|
5
|
+
ActiveSupport.on_load(:action_controller) do
|
6
|
+
include DataGrid::Controller
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
initializer "data_grid.view_helpers" do
|
11
|
+
ActionView::Base.send :include, DataGrid::ViewHelpers
|
12
|
+
end
|
13
|
+
|
14
|
+
initializer "static assets" do |app|
|
15
|
+
app.middleware.use ::ActionDispatch::Static, "#{root}/public"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Methods defined in this module are available as summary in DataGrid
|
2
|
+
|
3
|
+
module DataGrid
|
4
|
+
# Grid summaries
|
5
|
+
class Summaries
|
6
|
+
|
7
|
+
def self.average(a)
|
8
|
+
result = 0
|
9
|
+
unless a.blank?
|
10
|
+
a.each{|p| result += p.to_f}
|
11
|
+
result /= a.size
|
12
|
+
end
|
13
|
+
result.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.sum(a)
|
17
|
+
result = 0
|
18
|
+
a.each{|p| result += p.to_f} unless a.blank?
|
19
|
+
result.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.sum_price(a)
|
23
|
+
result = 0
|
24
|
+
unless a.blank?
|
25
|
+
a.each do |p|
|
26
|
+
result += p.match(/\-*\d+\,\d+/)[0].gsub(',', '.').to_f if p.match(/\d+\,\d+/) and p.match(/\d+\,\d+/)[0]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
result = sprintf("%.2f", result.to_f.round(2)).to_s
|
30
|
+
result
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|