widget_list 1.0.4 → 1.0.5

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/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