data_grid 0.0.1 → 0.0.2
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.
- 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
|
+
|