widget_list 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -20,6 +20,7 @@ In rails you have will_paginate and other ones like it using the ActiveRecord ap
20
20
  * Session rememberance for each list/view of what was last sorted, which page the person was on, the limit and search filters
21
21
  * Ability to set a cool custom HTML arrow which draws a hidden DIV intended for someone to put custom widgets inside of to pass new filters to the list before it executes
22
22
  * Buttons for each row and areas on the bottom of the grid where you can add "Action buttons"
23
+ * Export visible data as CSV
23
24
 
24
25
  ## Screenshots
25
26
 
@@ -51,6 +52,8 @@ Or install it yourself as:
51
52
 
52
53
  You can either follow the below instructions or take a look at the changes here https://github.com/davidrenne/widget_list_example/commit/e4e8ab54edcf8bc4538b1850ee762c13bc6f5316
53
54
 
55
+ I recommend if you use widget_list in production that you use config.consider_all_requests_local = true as errors will be handled but the base lists will still draw.
56
+
54
57
  ### #1 - Add widget_list CSS and JS to your application css and js
55
58
 
56
59
  Change application.css to:
@@ -87,28 +90,73 @@ You can either follow the below instructions or take a look at the changes here
87
90
  ### Example Calling Page That Sets up Config and calls WidgetList.render
88
91
 
89
92
 
90
- WidgetList::List.get_database.create_table :items do
91
- primary_key :id
92
- String :name
93
- Float :price
94
- Int :sku
95
- Date :date_added
93
+ #
94
+ # Load Sample "items" Data. Comment out in your first time executing a widgetlist to create the items table
95
+ #
96
+ begin
97
+ WidgetList::List.get_database.create_table :items do
98
+ primary_key :id
99
+ String :name
100
+ Float :price
101
+ Int :sku
102
+ Date :date_added
103
+ end
104
+ items = WidgetList::List.get_database[:items]
105
+ 100.times {
106
+ items.insert(:name => 'abc', :price => rand * 100, :date_added => '2008-02-01', :sku => 12345)
107
+ items.insert(:name => '123', :price => rand * 100, :date_added => '2008-02-02', :sku => 54321)
108
+ items.insert(:name => 'asdf', :price => rand * 100, :date_added => '2008-02-03', :sku => 67895)
109
+ items.insert(:name => 'qwerty', :price => rand * 100, :date_added => '2008-02-04', :sku => 66666)
110
+ items.insert(:name => 'poop', :price => rand * 100, :date_added => '2008-02-05', :sku => 77777)
111
+ }
112
+ rescue Exception => e
113
+ #
114
+ # Table already exists
115
+ #
116
+ logger.info "Test table in items already exists? " + e.to_s
96
117
  end
97
- items = WidgetList::List.get_database[:items]
98
- 100.times {
99
- items.insert(:name => 'abc', :price => rand * 100, :date_added => '2008-02-01', :sku => 12345)
100
- items.insert(:name => '123', :price => rand * 100, :date_added => '2008-02-02', :sku => 54321)
101
- items.insert(:name => 'asdf', :price => rand * 100, :date_added => '2008-02-03', :sku => 67895)
102
- items.insert(:name => 'qwerty', :price => rand * 100, :date_added => '2008-02-04', :sku => 66666)
103
- items.insert(:name => 'poop', :price => rand * 100, :date_added => '2008-02-05', :sku => 77777)
104
- }
105
118
 
119
+ list_parms = {}
120
+
121
+ #
122
+ # Give it a name, some SQL to feed widget_list and set a noDataMessage
123
+ #
124
+ list_parms['name'] = 'ruby_items_yum'
125
+
126
+ #
127
+ # Handle Dynamic Filters
128
+ #
129
+ if $_REQUEST.key?('switch_grouping') && $_REQUEST['switch_grouping'] == 'Item Name'
130
+ groupByFilter = 'item'
131
+ countSQL = 'COUNT(1) as cnt,'
132
+ groupBySQL = 'GROUP BY name'
133
+ elsif $_REQUEST.key?('switch_grouping') && $_REQUEST['switch_grouping'] == 'Sku Number'
134
+ groupByFilter = 'sku'
135
+ countSQL = 'COUNT(1) as cnt,'
136
+ groupBySQL = 'GROUP BY sku'
137
+ else
138
+ groupByFilter = 'none'
139
+ countSQL = ''
140
+ groupBySQL = ''
141
+ end
142
+
143
+ list_parms['filter'] = []
144
+ drillDown, filterValue = WidgetList::List::get_filter_and_drilldown(list_parms['name'])
145
+
146
+ case drillDown
147
+ when 'filter_by_name'
148
+ list_parms['filter'] << " name = '" + filterValue + "'"
149
+ when 'filter_by_sku'
150
+ list_parms['filter'] << " sku = '" + filterValue + "'"
151
+ end
152
+
153
+
154
+
106
155
  #
107
156
  # Setup your first widget_list
108
157
  #
109
158
 
110
159
  button_column_name = 'actions'
111
- list_parms = {}
112
160
 
113
161
  #
114
162
  # action_buttons will add buttons to the bottom of the list.
@@ -117,11 +165,24 @@ You can either follow the below instructions or take a look at the changes here
117
165
  action_buttons = WidgetList::Widgets::widget_button('Add New Item', {'page' => '/add/'} ) + WidgetList::Widgets::widget_button('Do something else', {'page' => '/else/'} )
118
166
 
119
167
  #
120
- # Give it a name, some SQL to feed widget_list and set a noDataMessage
168
+ # Give some SQL to feed widget_list and set a noDataMessage
121
169
  #
122
- list_parms['name'] = 'ruby_items_yum'
123
170
  list_parms['searchIdCol'] = ['id','sku']
124
- list_parms['view'] = '(SELECT \'\' as checkbox,a.* FROM items a ) a'
171
+ list_parms['view'] = '(
172
+ SELECT
173
+ ' + countSQL + '
174
+ ' + WidgetList::List::build_drill_down_link(list_parms['name'],'filter_by_name','a.name','a.name','name_linked') + '
175
+ ' + WidgetList::List::build_drill_down_link(list_parms['name'],'filter_by_sku','a.sku','a.sku','sku_linked') + '
176
+ \'\' AS checkbox,
177
+ a.id AS id,
178
+ a.name AS name,
179
+ a.sku AS sku,
180
+ a.price AS price,
181
+ a.date_added AS date_added
182
+ FROM
183
+ items a
184
+ ' + groupBySQL + '
185
+ ) a'
125
186
  list_parms['noDataMessage'] = 'No Ruby Items Found'
126
187
  list_parms['title'] = 'Ruby Items!!!'
127
188
 
@@ -133,7 +194,7 @@ You can either follow the below instructions or take a look at the changes here
133
194
  mini_buttons['button_edit'] = {'page' => '/edit',
134
195
  'text' => 'Edit',
135
196
  'function' => 'Redirect',
136
- #pass tags to pull from each column when building the URL
197
+ #pass tags to pull from each column when building the URL
137
198
  'tags' => {'my_key_name' => 'name','value_from_database'=>'price'}}
138
199
 
139
200
  mini_buttons['button_delete'] = {'page' => '/delete',
@@ -142,10 +203,10 @@ You can either follow the below instructions or take a look at the changes here
142
203
  'innerClass' => 'danger'}
143
204
  list_parms['buttons'] = {button_column_name => mini_buttons}
144
205
  list_parms['fieldFunction'] = {
145
- button_column_name => "''",
146
- 'date_added' => ['postgres','oracle'].include?(WidgetList::List.get_database.db_type) ? "TO_CHAR(date_added, 'MM/DD/YYYY')" : "date_added"
147
- }
148
- list_parms['groupByItems'] = ['All Records','Item Name']
206
+ button_column_name => "''",
207
+ 'date_added' => ['postgres','oracle'].include?(WidgetList::List.get_database.db_type) ? "TO_CHAR(date_added, 'MM/DD/YYYY')" : "date_added"
208
+ }
209
+ list_parms['groupByItems'] = ['All Records','Item Name', 'Sku Number']
149
210
 
150
211
  #
151
212
  # Generate a template for the DOWN ARROW for CUSTOM FILTER
@@ -166,10 +227,10 @@ You can either follow the below instructions or take a look at the changes here
166
227
  button_search['onclick'] = "alert('This would search, but is not coded. That is for you to do')"
167
228
 
168
229
  list_parms['list_search_form'] = WidgetList::Utils::fill( {
169
- '<!--COMMENTS-->' => WidgetList::Widgets::widget_input(input),
170
- '<!--BUTTON_SEARCH-->' => WidgetList::Widgets::widget_button('Search', button_search),
171
- '<!--BUTTON_CLOSE-->' => "HideAdvancedSearch(this)" } ,
172
- '
230
+ '<!--COMMENTS-->' => WidgetList::Widgets::widget_input(input),
231
+ '<!--BUTTON_SEARCH-->' => WidgetList::Widgets::widget_button('Search', button_search),
232
+ '<!--BUTTON_CLOSE-->' => "HideAdvancedSearch(this)" } ,
233
+ '
173
234
  <div id="advanced-search-container">
174
235
  <div class="widget-search-drilldown-close" onclick="<!--BUTTON_CLOSE-->">X</div>
175
236
  <ul class="advanced-search-container-inline" id="search_columns">
@@ -187,89 +248,94 @@ You can either follow the below instructions or take a look at the changes here
187
248
  #
188
249
 
189
250
  list_parms.deep_merge!({'fields' =>
190
- {
191
- 'checkbox'=> 'checkbox_header',
192
- }
193
- })
194
-
251
+ {
252
+ 'checkbox'=> 'checkbox_header',
253
+ }
254
+ })
255
+
195
256
  list_parms.deep_merge!({'fields' =>
196
- {
197
- 'id'=> 'Item Id',
198
- }
199
- })
200
-
257
+ {
258
+ 'cnt'=> 'Total Items In Group',
259
+ }
260
+ }) if groupByFilter != 'none'
261
+
262
+ list_parms.deep_merge!({'fields' =>
263
+ {
264
+ 'id'=> 'Item Id',
265
+ }
266
+ }) if groupByFilter == 'none'
267
+
201
268
  list_parms.deep_merge!({'fields' =>
202
- {
203
- 'name'=> 'Name',
204
- }
205
- })
206
-
269
+ {
270
+ 'name_linked'=> 'Name',
271
+ }
272
+ }) if groupByFilter == 'none' or groupByFilter == 'item'
273
+
207
274
  list_parms.deep_merge!({'fields' =>
208
- {
209
- 'price'=> 'Price of Item',
210
- }
211
- })
212
-
213
-
275
+ {
276
+ 'price'=> 'Price of Item',
277
+ }
278
+ }) if groupByFilter == 'none'
279
+
214
280
  list_parms.deep_merge!({'fields' =>
215
- {
216
- 'sku'=> 'Sku #',
217
- }
218
- })
219
-
281
+ {
282
+ 'sku_linked'=> 'Sku #',
283
+ }
284
+ }) if groupByFilter == 'none' or groupByFilter == 'sku'
285
+
220
286
  list_parms.deep_merge!({'fields' =>
221
- {
222
- 'date_added'=> 'Date Added',
223
- }
224
- })
225
-
287
+ {
288
+ 'date_added'=> 'Date Added',
289
+ }
290
+ }) if groupByFilter == 'none'
291
+
226
292
  list_parms.deep_merge!({'fields' =>
227
- {
228
- button_column_name => button_column_name.capitalize,
229
- }
230
- })
231
-
293
+ {
294
+ button_column_name => button_column_name.capitalize,
295
+ }
296
+ })
297
+
232
298
  #
233
299
  # Setup a custom field for checkboxes stored into the session and reloaded when refresh occurs
234
300
  #
235
301
 
236
302
  list_parms.deep_merge!({'inputs' =>
237
- {'checkbox'=>
238
- {'type' => 'checkbox'
239
- }
240
- }
241
- })
303
+ {'checkbox'=>
304
+ {'type' => 'checkbox'
305
+ }
306
+ }
307
+ })
242
308
 
243
309
  list_parms.deep_merge!({'inputs' =>
244
- {'checkbox'=>
245
- {'items' =>
246
- {
247
- 'name' => 'visible_checks[]',
248
- 'value' => 'id', #the value should be a column name mapping
249
- 'class_handle' => 'info_tables',
250
- }
251
- }
252
- }
253
- })
310
+ {'checkbox'=>
311
+ {'items' =>
312
+ {
313
+ 'name' => 'visible_checks[]',
314
+ 'value' => 'id', #the value should be a column name mapping
315
+ 'class_handle' => 'info_tables',
316
+ }
317
+ }
318
+ }
319
+ })
254
320
 
255
321
  list_parms.deep_merge!({'inputs' =>
256
- {'checkbox_header'=>
257
- {'type' => 'checkbox'
258
- }
259
- }
260
- })
322
+ {'checkbox_header'=>
323
+ {'type' => 'checkbox'
324
+ }
325
+ }
326
+ })
261
327
 
262
328
  list_parms.deep_merge!({'inputs' =>
263
- {'checkbox_header'=>
264
- {'items' =>
265
- {
266
- 'check_all' => true,
267
- 'id' => 'info_tables_check_all',
268
- 'class_handle' => 'info_tables',
269
- }
270
- }
271
- }
272
- })
329
+ {'checkbox_header'=>
330
+ {'items' =>
331
+ {
332
+ 'check_all' => true,
333
+ 'id' => 'info_tables_check_all',
334
+ 'class_handle' => 'info_tables',
335
+ }
336
+ }
337
+ }
338
+ })
273
339
 
274
340
  list = WidgetList::List.new(list_parms)
275
341
 
@@ -277,6 +343,11 @@ You can either follow the below instructions or take a look at the changes here
277
343
  # If AJAX, send back JSON
278
344
  #
279
345
  if $_REQUEST.key?('BUTTON_VALUE') && $_REQUEST['LIST_NAME'] == list_parms['name']
346
+ if $_REQUEST.key?('export_widget_list')
347
+ send_data(list.render(), :filename => list_parms['name'] + '.csv')
348
+ return
349
+ end
350
+
280
351
  ret = {}
281
352
  ret['list'] = WidgetList::Utils::fill({ '<!--CUSTOM_CONTENT-->' => action_buttons } , list.render() )
282
353
  ret['list_id'] = list_parms['name']
data/lib/widget_list.rb CHANGED
@@ -6,6 +6,7 @@ require 'widget_list/utils'
6
6
  require 'widget_list/tpl'
7
7
  require 'widget_list/widgets'
8
8
  require 'widget_list/railtie'
9
+ require 'csv'
9
10
  require 'json'
10
11
  require 'uri'
11
12
  require 'extensions/action_controller_base'
@@ -142,6 +143,10 @@ module WidgetList
142
143
  'searchFieldsIn' => {}, #White list of fields to include in a alpha-numeric based search
143
144
  'searchFieldsOut' => {'id'=>true}, #Black list of fields to include in a alpha-numeric based search (default `id` to NEVER search when alpha seach)
144
145
 
146
+ #
147
+ # Export
148
+ #
149
+ 'showExport' => true,
145
150
 
146
151
  #
147
152
  # Group By Box
@@ -210,6 +215,8 @@ module WidgetList
210
215
  'row_hooks' => {}
211
216
  }
212
217
 
218
+ @csv = []
219
+ @csv << []
213
220
  @totalRowCount= 0
214
221
  @totalPages = 0
215
222
  @fixHtmlLinksReplace = {}
@@ -536,7 +543,6 @@ module WidgetList
536
543
  fieldsToSearch.each { |fieldName,fieldTitle|
537
544
 
538
545
  # new lodgette. if fieldFunction exists, find all matches and skip them
539
- skip = false
540
546
 
541
547
  if @items['fieldFunction'].key?(fieldName)
542
548
  theField = @items['fieldFunction'][fieldName] + cast_col()
@@ -544,15 +550,8 @@ module WidgetList
544
550
  theField = tick_field() + "#{fieldName}" + cast_col() + tick_field()
545
551
  end
546
552
 
547
- (@items['inputs']||{}).each { |k,v|
548
- if fieldName == k
549
- skip = true
550
- end
551
- }
552
-
553
- if @items['buttons'].key?(fieldName)
554
- skip = true
555
- end
553
+ skip = false
554
+ skip = skip_column(fieldName)
556
555
 
557
556
  #buttons must ALWAYS BE ON THE RIGHT SIDE IN ORDER FOR THIS NOT TO SEARCH A NON-EXISTENT COLUMN (used to be hard coded to 'features' as a column to remove)
558
557
  if skip
@@ -661,6 +660,20 @@ module WidgetList
661
660
  end
662
661
  end
663
662
 
663
+ def skip_column(fieldName)
664
+ skip = false
665
+ (@items['inputs']||{}).each { |k,v|
666
+ if fieldName == k
667
+ skip = true
668
+ end
669
+ }
670
+
671
+ if @items['buttons'].key?(fieldName)
672
+ skip = true
673
+ end
674
+ return skip
675
+ end
676
+
664
677
  def tick_field()
665
678
  case WidgetList::List.get_database.db_type
666
679
  when 'postgres'
@@ -1019,9 +1032,15 @@ module WidgetList
1019
1032
  @templateFill['<!--FILTER_HEADER-->'] = ''
1020
1033
  end
1021
1034
  @templateFill['<!--FILTER_HEADER-->'] += '<div class="fake-select"><div class="label">' + @items['groupByLabel'] + ':</div> ' + WidgetList::Widgets::widget_input(list_group) + '</div>'
1035
+
1036
+ if @items['showExport']
1037
+ @templateFill['<!--FILTER_HEADER-->'] += WidgetList::Widgets::widget_button('Export CSV', {'onclick' => 'ListExport(\'' + @items['name'] + '\');'}, true)
1038
+ end
1039
+
1022
1040
  end
1023
1041
  end
1024
1042
  end
1043
+
1025
1044
  rescue Exception => e
1026
1045
  out = '<tr><td colspan="50"><div id="noListResults">' + generate_error_output(e) + @items['noDataMessage'] + '</div></td></tr>'
1027
1046
  if !@templateFill.key?('<!--DATA-->')
@@ -1031,8 +1050,15 @@ module WidgetList
1031
1050
  end
1032
1051
  end
1033
1052
 
1034
- return WidgetList::Utils::fill(@templateFill, @items['template'])
1035
-
1053
+ if $_REQUEST.key?('export_widget_list')
1054
+ csv = ''
1055
+ @csv.each{ |v|
1056
+ csv += v.to_csv
1057
+ }
1058
+ return csv
1059
+ else
1060
+ return WidgetList::Utils::fill(@templateFill, @items['template'])
1061
+ end
1036
1062
  end
1037
1063
 
1038
1064
  def build_pagination()
@@ -1292,6 +1318,12 @@ module WidgetList
1292
1318
  #
1293
1319
  fieldTitle = build_column_input(fieldTitle)
1294
1320
 
1321
+ else
1322
+
1323
+ if $_REQUEST.key?('export_widget_list') && !skip_column(field)
1324
+ @csv[0] << fieldTitle
1325
+ end
1326
+
1295
1327
  end
1296
1328
 
1297
1329
  if (@items['useSort'] && (@items['columnSort'].include?(field) || (@items['columnSort'].key?(field)) && !@items['columnNoSort'].include?(field)) || (@items['columnSort'].empty? && !@items['columnNoSort'].include?(field)))
@@ -1384,6 +1416,7 @@ module WidgetList
1384
1416
 
1385
1417
  headers << WidgetList::Utils::fill(pieces, @items[templateIdx])
1386
1418
  end
1419
+
1387
1420
  }
1388
1421
 
1389
1422
  @templateFill['<!--COLSPAN_FULL-->'] = headers.count()
@@ -1714,7 +1747,8 @@ module WidgetList
1714
1747
  rows = []
1715
1748
  j = 0
1716
1749
  for j in j..max
1717
- columns = []
1750
+ columns = []
1751
+ row_values = []
1718
1752
  customRowColor = ''
1719
1753
  customRowStyle = ''
1720
1754
 
@@ -1742,11 +1776,12 @@ module WidgetList
1742
1776
  #
1743
1777
  if @items['links'].key?(column) && @items['links'][column].class.name == 'Hash'
1744
1778
  onClick = build_column_link(column,j)
1779
+ end
1745
1780
 
1746
- #
1747
- # Column is a Button
1748
- #
1749
- elsif @items['buttons'].key?(column) && @items['buttons'][column].class.name == 'Hash'
1781
+ #
1782
+ # Column is a Button
1783
+ #
1784
+ if @items['buttons'].key?(column) && @items['buttons'][column].class.name == 'Hash'
1750
1785
  content = build_column_button(column, j)
1751
1786
 
1752
1787
 
@@ -1764,13 +1799,13 @@ module WidgetList
1764
1799
  else
1765
1800
  cleanData = strip_tags(@results[column.upcase][j].to_s)
1766
1801
 
1802
+ row_values << cleanData
1803
+
1767
1804
  #
1768
1805
  # For now disable length parser
1769
1806
  #
1770
1807
  if false && cleanData.length > @items['strlength']
1771
-
1772
1808
  content = @results[column.upcase][j].to_s[ 0, @items['strlength'] ] + '...'
1773
-
1774
1809
  else
1775
1810
  content = @results[column.upcase][j].to_s
1776
1811
  end
@@ -1781,6 +1816,7 @@ module WidgetList
1781
1816
  if !@items['allowHTML']
1782
1817
  content = strip_tags(content)
1783
1818
  end
1819
+
1784
1820
  content = WidgetList::List.get_database._bind(content, @items['bindVarsLegacy'])
1785
1821
 
1786
1822
  # Column color
@@ -1854,13 +1890,18 @@ module WidgetList
1854
1890
  colPieces['<!--ONCLICK-->'] = onClick
1855
1891
  colPieces['<!--TITLE-->'] = contentTitle #todo htmlentities needed ?
1856
1892
  colPieces['<!--CONTENT-->'] = content
1893
+
1857
1894
  #
1858
1895
  # Assemble the Column
1859
1896
  #
1860
1897
  columns << WidgetList::Utils::fill(colPieces, @items['col'])
1861
-
1862
1898
  }
1863
1899
 
1900
+
1901
+ if $_REQUEST.key?('export_widget_list')
1902
+ @csv << row_values
1903
+ end
1904
+
1864
1905
  #Draw the row
1865
1906
  #
1866
1907
 
@@ -1895,11 +1936,18 @@ module WidgetList
1895
1936
  @templateFill['<!--DATA-->'] = rows.join('')
1896
1937
 
1897
1938
  else
1898
- @templateFill['<!--DATA-->'] = '<tr><td colspan="50"><div id="noListResults">' + generate_error_output() + @items['noDataMessage'] + '</div></td></tr>'
1939
+
1940
+ err_message = (WidgetList::List.get_database.errors) ? @items['noDataMessage'] + ' <span style="color:red">(An error occurred)</span>' : @items['noDataMessage']
1941
+
1942
+ @templateFill['<!--DATA-->'] = '<tr><td colspan="50"><div id="noListResults">' + generate_error_output() + err_message + '</div></td></tr>'
1943
+
1899
1944
  end
1900
1945
 
1901
1946
  else
1902
- @templateFill['<!--DATA-->'] = '<tr><td colspan="50"><div id="noListResults">' + generate_error_output() + @items['noDataMessage'] + '</div></td></tr>'
1947
+
1948
+ err_message = (WidgetList::List.get_database.errors) ? @items['noDataMessage'] + ' <span style="color:red">(An error occurred)</span>' : @items['noDataMessage']
1949
+
1950
+ @templateFill['<!--DATA-->'] = '<tr><td colspan="50"><div id="noListResults">' + generate_error_output() + err_message + '</div></td></tr>'
1903
1951
  end
1904
1952
 
1905
1953
  end
@@ -2078,4 +2126,4 @@ module WidgetList
2078
2126
 
2079
2127
  end
2080
2128
 
2081
- endx
2129
+ end