widget_list 1.2.4 → 1.2.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,27 +1,35 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
18
-
19
- .idea/widget_list.iml
20
-
21
- .idea/widget_list.iml
22
-
23
- .idea/workspace.xml
24
-
25
- .DS_Store
26
-
27
- lib/widget_list (Autosaved).txt
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ .idea/widget_list.iml
20
+
21
+ .idea/widget_list.iml
22
+
23
+ .idea/workspace.xml
24
+
25
+ .DS_Store
26
+
27
+ lib/widget_list (Autosaved).txt
28
+
29
+ .idea/.rakeTasks
30
+
31
+ .idea/misc.xml
32
+
33
+ .idea/modules.xml
34
+
35
+ .idea/modules.xml
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in widget_list.gemspec
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in widget_list.gemspec
4
4
  gemspec
data/LICENSE.txt CHANGED
@@ -1,22 +1,22 @@
1
- Copyright (c) 2012 TODO: Write your name
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1
+ Copyright (c) 2012 TODO: Write your name
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,674 +1,713 @@
1
- # WidgetList
2
- ====================
3
-
4
- ****
5
-
6
- ## Introduction
7
-
8
- ****
9
-
10
- This is my first gem ever! It is an exciting gem because it is being used in production by a fortune 500 company. Please use and give me feedback/issues/pull requests.
11
-
12
- ****
13
-
14
- ## Summary
15
-
16
- ****
17
-
18
- I feel like there are not very good lists in ruby/rails and/or dont care to find any because nothing will compare to widget_list's implementation.
19
-
20
- In rails you have will_paginate and other ones like it using the ActiveRecord approach, but widget_list adds some awesome treats to standard boring pagers:
21
-
22
- * A sleek ajaxified list
23
- * Supports *ALL Databases (Haven't tested everything yet though, I am sure there are tweaks for each DB). mysql, postgres, oracle and sqllite tested (basic example)
24
- * Full sorting ASC/DESC and paging/limits of list via ajax
25
- * Easily add row level buttons for each row
26
- * Custom tags to pass to be replaced by actual data from each column/value
27
- * Automatic wildcard search support as well as CSV numeric parsing of when to perform a LIKE search or an IN statement on the primary keys
28
- * Column mappings and names
29
- * Drill down link helper functions to allow user to click and filter the list by the particular record value
30
- * Checkboxes for each row for custom selection and mass actions
31
- * Session rememberance for each list/view of what was last sorted, which page the person was on, the limit and search filters
32
- * Ability to set a 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
33
- * Buttons for each row and areas on the bottom of the grid where you can add "Action buttons"
34
- * Export visible data as CSV
35
- * Grouping/Predefined report filter feature
36
- * Either use a custom advanced searching form you build, or use the ransack dependency to build out a powerful filtering mechanism on the DOWN ARROW form users click. (See screenshots below)
37
- * Granular control over site-wide list parameter defaults using [A WidgetList Helper][1] or by simply copying the desired partial from the gem's app/views/widget_list/list_partials into your app/views/widget_list/list_partials and modifying the template for your "site-wide template" and outer list shells
38
- ** Support for theme plugins such as [The Blue Sky Basin Theme][2]
39
-
40
- ****
41
-
42
- ## Screenshots
43
-
44
- ****
45
-
46
- ### Main Example Loaded:
47
-
48
- ![](http://davidrenne.com/github/widget_list/main.png)
49
-
50
- ###Filter Drop Downs:
51
-
52
- ![](http://davidrenne.com/github/widget_list/filtered.png)
53
-
54
- ###Searching a row (with wild card search):
55
-
56
- ![](http://davidrenne.com/github/widget_list/search.png)
57
-
58
- ###Searching "name=asdf_18" (With ActiveRecord and Ransack hook):
59
-
60
- ![](http://davidrenne.com/github/widget_list/ransack1.png)
61
-
62
- ###Searching "name=asdf_18" and "sku<9000"(With ActiveRecord and Ransack hook):
63
-
64
- ![](http://davidrenne.com/github/widget_list/ransack2.png)
65
-
66
- ###Searching "name=asdf_18" and "sku < 9000" and "price > 67" (With ActiveRecord and Ransack hook):
67
-
68
- ![](http://davidrenne.com/github/widget_list/ransack3.png)
69
-
70
- ###Theme plugins/gem support ([The Blue Sky Basin Theme][2]):
71
-
72
- ![](http://davidrenne.com/github/widget_list/theme_blue_sky_basin.png)
73
-
74
-
75
- ****
76
-
77
- ## Installation
78
-
79
- ****
80
-
81
- Add this line to your application's Gemfile:
82
-
83
- ```ruby
84
- gem 'widget_list'
85
- ```
86
- And then execute:
87
- ```ruby
88
- $ bundle
89
- ```
90
- Or install it yourself as:
91
- ```ruby
92
- $ gem install widget_list
93
- ```
94
-
95
- ****
96
-
97
- ## Usage/Examples
98
-
99
- ****
100
-
101
- You can either follow the below instructions or take a look at the changes here https://github.com/davidrenne/widget_list_example/commit/e4e8ab54edcf8bc4538b1850ee762c13bc6f5316
102
-
103
- 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.
104
-
105
-
106
- ****
107
-
108
- ## Feature Configurations
109
-
110
- ****
111
-
112
- widget_list features and configurations primarily work by a single large hash passed to the constructor with the features you need for the given request which changes how the list is displayed or filtered.
113
-
114
- `name` - The unique name/id's of all the pieces that make up your widget list `default=([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(16).join`
115
-
116
- `database` - You can pass which DB connection you would like to use for each list. Only two values/db connections are supported ('primary' or 'secondary') `default='primary'`
117
-
118
- `title` - This adds an H1 title and horizontal rule on top of your list `default=''`
119
-
120
- `listDescription` - This adds a grey header box. It is useful for describing the main query `default=''`
121
-
122
- `pageId` - Base path for requests (typically you never need to change this) `default=$_SERVER['PATH_INFO']`
123
-
124
- `view` - A sub-select query to your database (ALWAYS ALIASED) `default=''`
125
-
126
- `data` - A "sequel" formatted resultset like would be returned from _select() method. Instead of running a SQL query, you can pass an array to populate the list `default={}`
127
-
128
- `collClass` - Your custom td class for all td's `default=''`
129
-
130
- `align` - td align attribute for all td's `default=''`
131
-
132
- `fields` - The visible fields shown in the current list. KEY=column name VALUE= displayed column header `default={}`
133
-
134
- `fieldsHidden` - The non-visible fields in the current list. Typically used when you wish to search on this column, but the main column is a drilldown or some HTML value that isnt easily searchable. VALUE=column name `default=[]`
135
-
136
- `bindVars` - bindVars that are passed to _select() sequel extension I wrote. Which will replace "?" in your query with the associated bindVar `default=[]`
137
-
138
- `bindVarsLegacy` - A Hash whose KEYS ARE CAPITALIZED and whose value is the replacement string. Inside the "view" you would use :MY_KEY as the template to be replaced `default={}`
139
-
140
- `links` - Turn text based record value into a link. KEY=column name VALUE=hash of link Config. Links should most likely pass ['tags']['field_name'] = 'get_var_name' (would yeild get_var_name=1234 for that field value 1234). You can pass ['tags']['onclick'] if you dont want to call ButtonLinkPost which will redirect to the URL built. If you pass ['onclick']['tags'], each field passed will be passed as a parameter for the function you designate `default={}`
141
-
142
- `buttons` - Buttons to generate for each row. KEY=column name VALUE=Hash of widget_button attributes `default={}`
143
-
144
- `inputs` - widget_check is the only one supported so far. (See examples) `default={}`
145
-
146
- `filter` - << "xxx = 123" would be the syntax to add a new filter array. (See examples) `default=[]`
147
-
148
- `groupBy` - The column name or CSV of names to group by. (See examples) `default=[]`
149
-
150
- `rowStart` - Which page the list should start at `default=0`
151
-
152
- `rowLimit` - How many rows per page? `default=10`
153
-
154
- `orderBy` - Default order by "column_name DIRECTION" `default=''`
155
-
156
- `allowHTML` - Strip HTML from view or not `default=true`
157
-
158
- `strlength` - Strip HTML from view or not `default=true`
159
-
160
- `searchClear` - Clear the list's search session `default=false`
161
-
162
- `searchClearAll` - Clear all search session for all lists `default=false`
163
-
164
- `showPagination` - Show pagination HTML `default=true`
165
-
166
- `searchSession` - Remember and restore the last search performed `default=true`
167
-
168
- `carryOverRequests` - will allow you to post custom things from request to all sort/paging URLS for each ajax. Takes an array of GETVARS which will be passed to each request `default=['switch_grouping']`
169
-
170
- `customFooter` - Add buttons or HTML at bottom area of list inside the grey box `default=''`
171
-
172
- `customHeader` - Add buttons or HTML at top area of list above all headers (such as TABS to delineate Summary/Details) `default=''`
173
-
174
- `ajaxFunctionAll` - Custom javascript called asychronously during each click of each event someone interacts with on the list `default=''`
175
-
176
- `ajaxFunction` - Mostly an internal setting `default='ListJumpMin'`
177
-
178
- `showSearch` - Show top search bar `default=true`
179
-
180
- `searchOnkeyup` - Search on key up event `default=''`
181
-
182
- `searchOnclick` - Search on click event `default=''`
183
-
184
- `searchIdCol` - By default `id` column is here because typically if you call your PK's id and are auto-increment and numeric. This can also take in an array of numeric fields so that users can search CSV's of numbers and get back matches `default='id'`
185
-
186
- `searchTitle` - Set a title for the search input `default= 'Search by Id or a list of Ids and more'`
187
-
188
- `searchFieldsIn` - White list of fields to include in a alpha-numeric based like '%%' search `default={}`
189
-
190
- `searchFieldsOut` - Black list of fields to exclude in a alpha-numeric based search `default={'id'=>true}`
191
-
192
- `showExport` - Allow users to export current list view as CSV `default=true`
193
-
194
- `exportButtonTitle` - Title of button `default='Export CSV'`
195
-
196
- `groupByItems` - Custom drop down's created by passing an array of modes. Best suited to group by the data `default=[]`
197
-
198
- `groupBySelected` - Initially selected grouping - defaults to first in list if not. Please pass the string value of the "groupByItem" `default=false`
199
-
200
- `groupByLabel` - Label describing select box `default='Group By'`
201
-
202
- `groupByClick` - Function to call as a custom function for each click on an item `default=''`
203
-
204
- `groupByClickDefault` - Default group by handler inside widget_list.js `default="ListChangeGrouping('<!--NAME-->', this);"`
205
-
206
- `listSearchForm` - Allows you to pass a custom form for the ARROW drop down for advanced searching `default=''`
207
-
208
- `ransackSearch` - If you pass ModelName.search(params[:q]) ransack will show up in your advanced search `default=false`
209
-
210
- `cornerRadius` - Either int number of pixels for radius corners. Or '14px' or whatever you want. `default=15`
211
-
212
- `columnStyle` - Column styles. KEY=column name VALUE= the inline style applied `default={}`
213
-
214
- `columnClass` - Column class. KEY=column name VALUE= the class name `default={}`
215
-
216
- `columnPopupTitle` - Column title as you hover over. KEY=column name VALUE=Popup text `default={}`
217
-
218
- `columnWidth` - Column widths. KEY=column name VALUE= '100px' `default={}`
219
-
220
- `columnNoSort` - Dont allow sorting on these columns (By default all visible columns have a sort link built). KEY=column name VALUE=column name `default={}`
221
-
222
- `borderedColumns` - Add a right border to each column. `default=false`
223
-
224
- `borderedRows` - Style the border of each row. `default=false`
225
-
226
- `borderRowStyle` - Border style of each row. `default='1px solid #CCCCCC'`
227
-
228
- `borderHeadFoot` - Style the border of header (bottom) and footer (top). `default=false`
229
-
230
- `headFootBorderStyle` - Border style of header (bottom) and footer (top). `default='1px solid #CCCCCC'`
231
-
232
- `borderColumnStyle` - Style of row if you use this above feature. `default='1px solid #CCCCCC'`
233
-
234
- `bordersEverywhere?` - If true, use borderEverywhere for all four borders you can pass separately `default=false`
235
-
236
- `borderEverywhere` - The catch all style of borders for headers, rows, outer table border and columns. `default='1px solid #CCCCCC'`
237
-
238
- `defaultButtonClass` - As you have seen in many screenshots, there are several buttons. This controls the innerClass of those drawn from the list. See lib/widget_list/widgets.rb `default='info'`
239
-
240
- `useBoxShadow` - Show shadow or not on list `default=true`
241
-
242
- `shadowInset` - Number or string with '11Px' for an 11PX Inset `default=10`
243
-
244
- `shadowSpread` - Number or string with '11Px' for an 11PX spread `default=20`
245
-
246
- `shadowColor` - Color of bottom right shadow `default='shadowColor'`
247
-
248
- `rowClass` - Class added to all rows `default=''`
249
-
250
- `rowFontColor` - Font color of all data rows that dont have a rowStylesByStatus color: passed to it `default='black'`
251
-
252
- `rowColorByStatus` - {'rowColorByStatus' =>
253
- {'active'=>
254
- {'No' => '#EBEBEB' }
255
- }
256
- }
257
- Color a row based on the value of the column.
258
- `default={}`
259
-
260
- `rowStylesByStatus` - {'rowStylesByStatus' =>
261
- {'active'=>
262
- {'No' => 'font-style:italic;color:red;' }
263
- }
264
- }
265
- Style a row based on the value of the column.
266
- `default={}`
267
-
268
- `rowOffsets` - Color for each row and offset `default=['FFFFFF','FFFFFF']`
269
-
270
- `noDataMessage` - Message to show when no data is found `default='Currently no data.'`
271
-
272
- `useSort` - Allow sorting on list `default=true`
273
-
274
- `headerClass` - Class of each individual header column `default={}`
275
-
276
- `fieldFunction` - A way to wrap or inject columns or SQL formatting in place of your columns `default={}`
277
-
278
- `template` - Pass in a custom template for outer shell `default=''`
279
-
280
- `templateFilter` - Instead of widget list building your search box. Pass your own HTML `default=''`
281
-
282
- `storeSessionChecks` - See http://stackoverflow.com/questions/1928204/marshal-data-too-short for configuring larger session storage which checkboxes would eat up if you had this set to true `default=false`
283
-
284
- `columnHooks` - Todo `default={}`
285
-
286
- `rowHooks` - Todo `default={}`
287
-
288
-
289
- ### #1 - Add widget_list CSS and JS to your application css and js
290
-
291
- Change application.css to:
292
- ```ruby
293
- *= require widget_list
294
- *= require widgets
295
- ```
296
- Change application.js to:
297
- ```ruby
298
- //= require widget_list
299
- ```
300
- ### #2 - Run `bundle exec rails s` to have widget_list create config/widget-list.yml (by default a sqlite3 memory database is created)
301
-
302
- Configure your connection settings for your primary or secondary widget_list connections.
303
-
304
- http://sequel.rubyforge.org/rdoc/files/doc/opening_databases_rdoc.html
305
-
306
- ### #3 - If you wish to integrate into an existing rails application create a new controller
307
-
308
- rails generate controller WidgetListExamples ruby_items
309
-
310
- Then modify app/views/widget_list_examples/ruby_items.html.erb and add
311
- ```ruby
312
- <div style="margin:50px;">
313
- <%=raw @output%>
314
- </div>
315
- ```
316
- Add config/routes.rb if it is not in there:
317
- ```ruby
318
- match ':controller(/:action)'
319
- ```
320
- Ensure that sessions are loaded into active record because widget_list keeps track of several settings on each list for each session
321
- ```ruby
322
- config.session_store :active_record_store
323
- ```
324
- Add the example shown below to app/controllers/widget_list_examples_controller.rb#ruby_items
325
-
326
- Go To http://localhost:3000/widget_list_examples/ruby_items
327
-
328
- ****
329
-
330
- ### Example Calling Page That Sets up Config and calls WidgetList.render
331
-
332
- ****
333
-
334
- ```ruby
335
- #
336
- # Load Sample "items" Data. Comment out in your first time executing a widgetlist to create the items table
337
- #
338
- =begin
339
- begin
340
- WidgetList::List.get_sequel.create_table :items do
341
- primary_key :id
342
- String :name
343
- Float :price
344
- Fixnum :sku
345
- String :active
346
- Date :date_added
347
- end
348
- items = WidgetList::List.get_sequel[:items]
349
- 100.times {
350
- items.insert(:name => 'ab\'c_quoted_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-01', :sku => rand(9999), :active => 'Yes')
351
- items.insert(:name => '12"3_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-02', :sku => rand(9999), :active => 'Yes')
352
- items.insert(:name => 'asdf_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-03', :sku => rand(9999), :active => 'Yes')
353
- items.insert(:name => 'qwerty_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-04', :sku => rand(9999), :active => 'No')
354
- items.insert(:name => 'meow_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-05', :sku => rand(9999), :active => 'No')
355
- }
356
- rescue Exception => e
357
- #
358
- # Table already exists
359
- #
360
- logger.info "Test table in items already exists? " + e.to_s
361
- end
362
- =end
363
-
364
- begin
365
-
366
- list_parms = WidgetList::List::init_config()
367
-
368
- #
369
- # Give it a name, some SQL to feed widget_list and set a noDataMessage
370
- #
371
- list_parms['name'] = 'ruby_items_yum'
372
-
373
- #
374
- # Handle Dynamic Filters
375
- #
376
- groupBy = WidgetList::List::get_group_by_selection(list_parms)
377
-
378
- case groupBy
379
- when 'Item Name'
380
- groupByFilter = 'item'
381
- countSQL = 'COUNT(1) as cnt,'
382
- groupBySQL = 'GROUP BY name'
383
- groupByDesc = ' (Grouped By Name)'
384
- when 'Sku Number'
385
- groupByFilter = 'sku'
386
- countSQL = 'COUNT(1) as cnt,'
387
- groupBySQL = 'GROUP BY sku'
388
- groupByDesc = ' (Grouped By Sku Number)'
389
- else
390
- groupByFilter = 'none'
391
- countSQL = ''
392
- groupBySQL = ''
393
- groupByDesc = ''
394
- end
395
-
396
- list_parms['filter'] = []
397
- list_parms['bindVars'] = []
398
- drillDown, filterValue = WidgetList::List::get_filter_and_drilldown(list_parms['name'])
399
-
400
- case drillDown
401
- when 'filter_by_name'
402
- list_parms['filter'] << " name = ? "
403
- list_parms['bindVars'] << filterValue
404
- list_parms['listDescription'] = WidgetList::List::drill_down_back(list_parms['name']) + ' Filtered by Name (' + filterValue + ')' + groupByDesc
405
- when 'filter_by_sku'
406
- list_parms['filter'] << " sku = ? "
407
- list_parms['bindVars'] << filterValue
408
- list_parms['listDescription'] = WidgetList::List::drill_down_back(list_parms['name']) + ' Filtered by SKU (' + filterValue + ')' + groupByDesc
409
- else
410
- list_parms['listDescription'] = ''
411
- list_parms['listDescription'] = WidgetList::List::drill_down_back(list_parms['name']) if !groupByDesc.empty?
412
- list_parms['listDescription'] += 'Showing All Ruby Items' + groupByDesc
413
- end
414
-
415
- # put <%= @output %> inside your view for initial load nothing to do here other than any custom concatenation of multiple lists
416
- #
417
- # Setup your first widget_list
418
- #
419
-
420
- button_column_name = 'actions'
421
-
422
- #
423
- # customFooter will add buttons to the bottom of the list.
424
- #
425
-
426
- list_parms['customFooter'] = WidgetList::Widgets::widget_button('Add New Item', {'page' => '/add/'} ) + WidgetList::Widgets::widget_button('Do something else', {'page' => '/else/'} )
427
-
428
- #
429
- # Give some SQL to feed widget_list and set a noDataMessage
430
- #
431
- list_parms['searchIdCol'] = ['id','sku']
432
-
433
- #
434
- # Because sku_linked column is being used and the raw SKU is hidden, we need to make this available for searching via fields_hidden
435
- #
436
- list_parms['fieldsHidden'] = ['sku']
437
-
438
- drill_downs = []
439
-
440
- drill_downs << WidgetList::List::build_drill_down( :list_id => list_parms['name'],
441
- :drill_down_name => 'filter_by_name',
442
- :data_to_pass_from_view => 'a.name',
443
- :column_to_show => 'a.name',
444
- :column_alias => 'name_linked'
445
- )
446
-
447
- drill_downs << WidgetList::List::build_drill_down(
448
- :list_id => list_parms['name'],
449
- :drill_down_name => 'filter_by_sku',
450
- :data_to_pass_from_view => 'a.sku',
451
- :column_to_show => 'a.sku',
452
- :column_alias => 'sku_linked'
453
- )
454
-
455
- list_parms['view'] = '(
456
- SELECT
457
- ' + countSQL + '
458
- ' + drill_downs.join(' , ') + ',
459
- \'\' AS checkbox,
460
- a.id AS id,
461
- a.active AS active,
462
- a.name AS name,
463
- a.sku AS sku,
464
- a.price AS price,
465
- a.date_added AS date_added
466
- FROM
467
- items a
468
- ' + groupBySQL + '
469
- ) a'
470
-
471
- #
472
- # Map out the visible fields
473
- #
474
- list_parms['fields'] = {}
475
- list_parms['fields']['checkbox'] = 'checkbox_header'
476
- list_parms['fields']['cnt'] = 'Total Items In Group' if groupByFilter != 'none'
477
- list_parms['fields']['id'] = 'Item Id' if groupByFilter == 'none'
478
- list_parms['fields']['name_linked'] = 'Name' if groupByFilter == 'none' or groupByFilter == 'item'
479
- list_parms['fields']['price'] = 'Price of Item' if groupByFilter == 'none'
480
- list_parms['fields']['sku_linked'] = 'Sku #' if groupByFilter == 'none' or groupByFilter == 'sku'
481
- list_parms['fields']['date_added'] = 'Date Added' if groupByFilter == 'none'
482
- list_parms['fields']['active'] = 'Active Item' if groupByFilter == 'none'
483
- list_parms['fields'][button_column_name] = button_column_name.capitalize if groupByFilter == 'none'
484
-
485
-
486
- list_parms['noDataMessage'] = 'No Ruby Items Found'
487
- list_parms['title'] = 'Ruby Items Using Sequel!!!'
488
-
489
- #
490
- # Create small button array and pass to the buttons key
491
- #
492
-
493
- mini_buttons = {}
494
- mini_buttons['button_edit'] = {'page' => '/edit',
495
- 'text' => 'Edit',
496
- 'function' => 'Redirect',
497
- #pass tags to pull from each column when building the URL
498
- 'tags' => {'my_key_name' => 'name','value_from_database'=>'price'}}
499
-
500
- mini_buttons['button_delete'] = {'page' => '/delete',
501
- 'text' => 'Delete',
502
- 'function' => 'alert',
503
- 'innerClass' => 'danger'}
504
- list_parms['buttons'] = {button_column_name => mini_buttons}
505
- list_parms['fieldFunction'] = {
506
- button_column_name => "''",
507
- 'date_added' => ['postgres','oracle'].include?(WidgetList::List::get_db_type) ? "TO_CHAR(date_added, 'MM/DD/YYYY')" : "date_added"
508
- }
509
-
510
- list_parms['groupByItems'] = ['All Records', 'Item Name', 'Sku Number']
511
-
512
-
513
- #
514
- # Setup a custom field for checkboxes stored into the session and reloaded when refresh occurs
515
- #
516
- list_parms = WidgetList::List.checkbox_helper(list_parms,'id')
517
-
518
- #
519
- # Generate a template for the DOWN ARROW for CUSTOM FILTER
520
- #
521
- input = {}
522
-
523
- input['id'] = 'comments'
524
- input['name'] = 'comments'
525
- input['width'] = '170'
526
- input['max_length'] = '500'
527
- input['input_class'] = 'info-input'
528
- input['title'] = 'Optional CSV list'
529
-
530
- button_search = {}
531
- button_search['onclick'] = "alert('This would search, but is not coded. That is for you to do')"
532
-
533
- list_parms['listSearchForm'] = WidgetList::Utils::fill( {
534
- '<!--BUTTON_SEARCH-->' => WidgetList::Widgets::widget_button('Search', button_search),
535
- '<!--COMMENTS-->' => WidgetList::Widgets::widget_input(input),
536
- '<!--BUTTON_CLOSE-->' => "HideAdvancedSearch(this)" } ,
537
- '
538
- <div id="advanced-search-container">
539
- <div class="widget-search-drilldown-close" onclick="<!--BUTTON_CLOSE-->">X</div>
540
- <ul class="advanced-search-container-inline" id="search_columns">
541
- <li>
542
- <div>Search Comments</div>
543
- <!--COMMENTS-->
544
- </li>
545
- </ul>
546
- <br/>
547
- <div style="text-align:right;width:100%;height:30px;" class="advanced-search-container-buttons"><!--BUTTON_RESET--><!--BUTTON_SEARCH--></div>
548
- </div>'
549
- # or to keep HTML out of controller render_to_string(:partial => 'partials/form_xxx')
550
- )
551
-
552
- #
553
- # Control widths of special fields
554
- #
555
-
556
- list_parms['columnWidth'] = {
557
- 'date_added'=>'200px',
558
- 'sku_linked'=>'20px',
559
- }
560
-
561
- #
562
- # If certain statuses of records are shown, visualize
563
- #
564
-
565
- list_parms.deep_merge!({'rowStylesByStatus' =>
566
- {'active'=>
567
- {'Yes' => '' }
568
- }
569
- })
570
- list_parms.deep_merge!({'rowStylesByStatus' =>
571
- {'active'=>
572
- {'No' => 'font-style:italic;color:red;' }
573
- }
574
- })
575
-
576
- list_parms.deep_merge!({'rowColorByStatus' =>
577
- {'active'=>
578
- {'Yes' => '' }
579
- }
580
- })
581
- list_parms.deep_merge!({'rowColorByStatus' =>
582
- {'active'=>
583
- {'No' => '#EBEBEB' }
584
- }
585
- })
586
-
587
-
588
- list_parms['columnPopupTitle'] = {}
589
- list_parms['columnPopupTitle']['checkbox'] = 'Select any record'
590
- list_parms['columnPopupTitle']['cnt'] = 'Total Count'
591
- list_parms['columnPopupTitle']['id'] = 'The primary key of the item'
592
- list_parms['columnPopupTitle']['name_linked'] = 'Name (Click to drill down)'
593
- list_parms['columnPopupTitle']['price'] = 'Price of item (not formatted)'
594
- list_parms['columnPopupTitle']['sku_linked'] = 'Sku # (Click to drill down)'
595
- list_parms['columnPopupTitle']['date_added'] = 'The date the item was added to the database'
596
- list_parms['columnPopupTitle']['active'] = 'Is the item active?'
597
-
598
- output_type, output = WidgetList::List.build_list(list_parms)
599
-
600
- case output_type
601
- when 'html'
602
- # put <%= @output %> inside your view for initial load nothing to do here other than any custom concatenation of multiple lists
603
- @output = output
604
- when 'json'
605
- return render :inline => output
606
- when 'export'
607
- send_data(output, :filename => list_parms['name'] + '.csv')
608
- return
609
- end
610
-
611
- rescue Exception => e
612
-
613
- Rails.logger.info e.to_s + "\n\n" + $!.backtrace.join("\n\n")
614
-
615
- #really this block is just to catch initial ruby errors in setting up your list_parms
616
- #I suggest taking out this rescue when going to production
617
- output_type, output = WidgetList::List.build_list(list_parms)
618
-
619
- case output_type
620
- when 'html'
621
- @output = output
622
- when 'json'
623
- return render :inline => output
624
- when 'export'
625
- send_data(output, :filename => list_parms['name'] + '.csv')
626
- return
627
- end
628
-
629
- end
630
- ```
631
-
632
- ****
633
-
634
- ## Contributing
635
-
636
- ****
637
-
638
- 1. Fork it
639
- 2. Create your feature branch (`git checkout -b my-new-feature`)
640
- 3. Commit your changes (`git commit -am 'Add some feature'`)
641
- 4. Push to the branch (`git push origin my-new-feature`)
642
- 5. Create new Pull Request
643
-
644
-
645
- Meta
646
- ----
647
-
648
- * Gems: <https://rubygems.org/gems/widget_list>
649
-
650
-
651
- Authors
652
- -------
653
-
654
- David Renne :: david_renne @ ya hoo - .com :: @phpnerd
655
-
656
- License
657
- -------
658
-
659
- Copyright 2012 David Renne
660
-
661
- Licensed under the Apache License, Version 2.0 (the "License");
662
- you may not use this file except in compliance with the License.
663
- You may obtain a copy of the License at
664
-
665
- http://www.apache.org/licenses/LICENSE-2.0
666
-
667
- Unless required by applicable law or agreed to in writing, software
668
- distributed under the License is distributed on an "AS IS" BASIS,
669
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
670
- See the License for the specific language governing permissions and
671
- limitations under the License.
672
-
673
- [1]: https://github.com/davidrenne/widget_list_example/blob/master/app/helpers/widget_list_helper.rb
1
+ # WidgetList
2
+ ====================
3
+
4
+ ****
5
+
6
+ ## Introduction
7
+
8
+ ****
9
+
10
+ This is my first gem ever! It is an exciting gem because it is being used in production by a fortune 500 company. Please use and give me feedback/issues/pull requests.
11
+
12
+ ****
13
+
14
+ ## Summary
15
+
16
+ ****
17
+
18
+ I feel like there are not very good lists in ruby/rails and/or dont care to find any because nothing will compare to widget_list's implementation.
19
+
20
+ In rails you have will_paginate and other ones like it using the ActiveRecord approach, but widget_list adds some awesome treats to standard boring pagers:
21
+
22
+ * A sleek ajaxified list
23
+ * Full Blown configuration administration tool
24
+ * Supports *ALL Databases (Haven't tested everything yet though, I am sure there are tweaks for each DB). mysql, postgres, oracle and sqllite tested (basic example)
25
+ * Full sorting ASC/DESC and paging/limits of list via ajax
26
+ * Easily add row level buttons for each row
27
+ * Custom tags to pass to be replaced by actual data from each column/value
28
+ * Automatic wildcard search support as well as CSV numeric parsing of when to perform a LIKE search or an IN statement on the primary keys
29
+ * Column mappings and names
30
+ * Drill down link helper functions to allow user to click and filter the list by the particular record value
31
+ * Checkboxes for each row for custom selection and mass actions
32
+ * Session rememberance for each list/view of what was last sorted, which page the person was on, the limit and search filters
33
+ * Ability to set a 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
34
+ * Buttons for each row and areas on the bottom of the grid where you can add "Action buttons"
35
+ * Export visible data as CSV
36
+ * Grouping/Predefined report filter feature
37
+ * Either use a custom advanced searching form you build, or use the ransack dependency to build out a powerful filtering mechanism on the DOWN ARROW form users click. (See screenshots below)
38
+ * Granular control over site-wide list parameter defaults using [A WidgetList Helper][1] or by simply copying the desired partial from the gem's app/views/widget_list/list_partials into your app/views/widget_list/list_partials and modifying the template for your "site-wide template" and outer list shells
39
+ ** Support for theme plugins such as [The Blue Sky Basin Theme][2]
40
+
41
+ ****
42
+
43
+ ## Screenshots
44
+
45
+ ****
46
+
47
+ ### Main Example Loaded:
48
+
49
+ ![](http://davidrenne.com/github/widget_list/main.png)
50
+
51
+ ###Filter Drop Downs:
52
+
53
+ ![](http://davidrenne.com/github/widget_list/filtered.png)
54
+
55
+ ###Searching a row (with wild card search):
56
+
57
+ ![](http://davidrenne.com/github/widget_list/search.png)
58
+
59
+ ###Searching "name=asdf_18" (With ActiveRecord and Ransack hook):
60
+
61
+ ![](http://davidrenne.com/github/widget_list/ransack1.png)
62
+
63
+ ###Searching "name=asdf_18" and "sku<9000"(With ActiveRecord and Ransack hook):
64
+
65
+ ![](http://davidrenne.com/github/widget_list/ransack2.png)
66
+
67
+ ###Searching "name=asdf_18" and "sku < 9000" and "price > 67" (With ActiveRecord and Ransack hook):
68
+
69
+ ![](http://davidrenne.com/github/widget_list/ransack3.png)
70
+
71
+ ###Theme plugins/gem support ([The Blue Sky Basin Theme][2]):
72
+
73
+ ![](http://davidrenne.com/github/widget_list/theme_blue_sky_basin.png)
74
+
75
+ ****
76
+
77
+ ## Administration Tool
78
+
79
+ ****
80
+
81
+ In order to use this tool please paste your @output into your view
82
+
83
+ ```ruby
84
+ <div style="margin:50px;">
85
+ <%=raw @output%>
86
+ </div>
87
+ ```
88
+
89
+ And then add this to a clean controller. If you have code below, please return below the ajax
90
+
91
+ ```ruby
92
+ @output = WidgetList.go!()
93
+ return render :inline => @output if params.key?('ajax')
94
+ ```
95
+
96
+ Next you will see this interface which will build some starter code for you:
97
+
98
+ ![](http://davidrenne.com/github/widget_list/admin1.jpg)
99
+
100
+ ![](http://davidrenne.com/github/widget_list/admin2.jpg)
101
+
102
+ ![](http://davidrenne.com/github/widget_list/admin3.jpg)
103
+
104
+ ![](http://davidrenne.com/github/widget_list/admin4.jpg)
105
+
106
+ ###As you can see below, there is a preview iframe of what you are configuring:
107
+
108
+ ![](http://davidrenne.com/github/widget_list/admin5.png)
109
+
110
+ ###And finally, the code is output to get you started
111
+
112
+ ![](http://davidrenne.com/github/widget_list/admin6.png)
113
+
114
+ ****
115
+
116
+ ## Installation
117
+
118
+ ****
119
+
120
+ Add this line to your application's Gemfile:
121
+
122
+ ```ruby
123
+ gem 'widget_list'
124
+ ```
125
+ And then execute:
126
+ ```ruby
127
+ $ bundle
128
+ ```
129
+ Or install it yourself as:
130
+ ```ruby
131
+ $ gem install widget_list
132
+ ```
133
+
134
+ ****
135
+
136
+ ## Usage/Examples
137
+
138
+ ****
139
+
140
+ You can either follow the below instructions or take a look at the changes here https://github.com/davidrenne/widget_list_example/commit/e4e8ab54edcf8bc4538b1850ee762c13bc6f5316
141
+
142
+ 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.
143
+
144
+
145
+ ****
146
+
147
+ ## Feature Configurations
148
+
149
+ ****
150
+
151
+ widget_list features and configurations primarily work by a single large hash passed to the constructor with the features you need for the given request which changes how the list is displayed or filtered.
152
+
153
+ `name` - The unique name/id's of all the pieces that make up your widget list `default=([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(16).join`
154
+
155
+ `database` - You can pass which DB connection you would like to use for each list. Only two values/db connections are supported ('primary' or 'secondary') `default='primary'`
156
+
157
+ `title` - This adds an H1 title and horizontal rule on top of your list `default=''`
158
+
159
+ `listDescription` - This adds a grey header box. It is useful for describing the main query `default=''`
160
+
161
+ `pageId` - Base path for requests (typically you never need to change this) `default=$_SERVER['PATH_INFO']`
162
+
163
+ `view` - A sub-select query to your database (ALWAYS ALIASED) `default=''`
164
+
165
+ `data` - A "sequel" formatted resultset like would be returned from _select() method. Instead of running a SQL query, you can pass an array to populate the list `default={}`
166
+
167
+ `collClass` - Your custom td class for all td's `default=''`
168
+
169
+ `align` - td align attribute for all td's `default=''`
170
+
171
+ `fields` - The visible fields shown in the current list. KEY=column name VALUE= displayed column header `default={}`
172
+
173
+ `fieldsHidden` - The non-visible fields in the current list. Typically used when you wish to search on this column, but the main column is a drilldown or some HTML value that isnt easily searchable. VALUE=column name `default=[]`
174
+
175
+ `bindVars` - bindVars that are passed to _select() sequel extension I wrote. Which will replace "?" in your query with the associated bindVar `default=[]`
176
+
177
+ `bindVarsLegacy` - A Hash whose KEYS ARE CAPITALIZED and whose value is the replacement string. Inside the "view" you would use :MY_KEY as the template to be replaced `default={}`
178
+
179
+ `links` - Turn text based record value into a link. KEY=column name VALUE=hash of link Config. Links should most likely pass ['tags']['field_name'] = 'get_var_name' (would yeild get_var_name=1234 for that field value 1234). You can pass ['tags']['onclick'] if you dont want to call ButtonLinkPost which will redirect to the URL built. If you pass ['onclick']['tags'], each field passed will be passed as a parameter for the function you designate `default={}`
180
+
181
+ `buttons` - Buttons to generate for each row. KEY=column name VALUE=Hash of widget_button attributes `default={}`
182
+
183
+ `inputs` - widget_check is the only one supported so far. (See examples) `default={}`
184
+
185
+ `filter` - << "xxx = 123" would be the syntax to add a new filter array. (See examples) `default=[]`
186
+
187
+ `groupBy` - The column name or CSV of names to group by. (See examples) `default=[]`
188
+
189
+ `rowStart` - Which page the list should start at `default=0`
190
+
191
+ `rowLimit` - How many rows per page? `default=10`
192
+
193
+ `orderBy` - Default order by "column_name DIRECTION" `default=''`
194
+
195
+ `allowHTML` - Strip HTML from view or not `default=true`
196
+
197
+ `strlength` - Strip HTML from view or not `default=true`
198
+
199
+ `searchClear` - Clear the list's search session `default=false`
200
+
201
+ `searchClearAll` - Clear all search session for all lists `default=false`
202
+
203
+ `showPagination` - Show pagination HTML `default=true`
204
+
205
+ `searchSession` - Remember and restore the last search performed `default=true`
206
+
207
+ `carryOverRequests` - will allow you to post custom things from request to all sort/paging URLS for each ajax. Takes an array of GETVARS which will be passed to each request `default=['switch_grouping']`
208
+
209
+ `customFooter` - Add buttons or HTML at bottom area of list inside the grey box `default=''`
210
+
211
+ `customHeader` - Add buttons or HTML at top area of list above all headers (such as TABS to delineate Summary/Details) `default=''`
212
+
213
+ `ajaxFunctionAll` - Custom javascript called asychronously during each click of each event someone interacts with on the list `default=''`
214
+
215
+ `ajaxFunction` - Mostly an internal setting `default='ListJumpMin'`
216
+
217
+ `showSearch` - Show top search bar `default=true`
218
+
219
+ `searchOnkeyup` - Search on key up event `default=''`
220
+
221
+ `searchOnclick` - Search on click event `default=''`
222
+
223
+ `searchIdCol` - By default `id` column is here because typically if you call your PK's id and are auto-increment and numeric. This can also take in an array of numeric fields so that users can search CSV's of numbers and get back matches `default='id'`
224
+
225
+ `searchTitle` - Set a title for the search input `default= 'Search by Id or a list of Ids and more'`
226
+
227
+ `searchFieldsIn` - White list of fields to include in a alpha-numeric based like '%%' search `default={}`
228
+
229
+ `searchFieldsOut` - Black list of fields to exclude in a alpha-numeric based search `default={'id'=>true}`
230
+
231
+ `showExport` - Allow users to export current list view as CSV `default=true`
232
+
233
+ `exportButtonTitle` - Title of button `default='Export CSV'`
234
+
235
+ `groupByItems` - Custom drop down's created by passing an array of modes. Best suited to group by the data `default=[]`
236
+
237
+ `groupBySelected` - Initially selected grouping - defaults to first in list if not. Please pass the string value of the "groupByItem" `default=false`
238
+
239
+ `groupByLabel` - Label describing select box `default='Group By'`
240
+
241
+ `groupByClick` - Function to call as a custom function for each click on an item `default=''`
242
+
243
+ `groupByClickDefault` - Default group by handler inside widget_list.js `default="ListChangeGrouping('<!--NAME-->', this);"`
244
+
245
+ `listSearchForm` - Allows you to pass a custom form for the ARROW drop down for advanced searching `default=''`
246
+
247
+ `ransackSearch` - If you pass ModelName.search(params[:q]) ransack will show up in your advanced search `default=false`
248
+
249
+ `cornerRadius` - Either int number of pixels for radius corners. Or '14px' or whatever you want. `default=15`
250
+
251
+ `columnStyle` - Column styles. KEY=column name VALUE= the inline style applied `default={}`
252
+
253
+ `columnClass` - Column class. KEY=column name VALUE= the class name `default={}`
254
+
255
+ `columnPopupTitle` - Column title as you hover over. KEY=column name VALUE=Popup text `default={}`
256
+
257
+ `columnWidth` - Column widths. KEY=column name VALUE= '100px' `default={}`
258
+
259
+ `columnNoSort` - Dont allow sorting on these columns (By default all visible columns have a sort link built). KEY=column name VALUE=column name `default={}`
260
+
261
+ `borderedColumns` - Add a right border to each column. `default=false`
262
+
263
+ `borderedRows` - Style the border of each row. `default=false`
264
+
265
+ `borderRowStyle` - Border style of each row. `default='1px solid #CCCCCC'`
266
+
267
+ `borderHeadFoot` - Style the border of header (bottom) and footer (top). `default=false`
268
+
269
+ `headFootBorderStyle` - Border style of header (bottom) and footer (top). `default='1px solid #CCCCCC'`
270
+
271
+ `borderColumnStyle` - Style of row if you use this above feature. `default='1px solid #CCCCCC'`
272
+
273
+ `bordersEverywhere?` - If true, use borderEverywhere for all four borders you can pass separately `default=false`
274
+
275
+ `borderEverywhere` - The catch all style of borders for headers, rows, outer table border and columns. `default='1px solid #CCCCCC'`
276
+
277
+ `defaultButtonClass` - As you have seen in many screenshots, there are several buttons. This controls the innerClass of those drawn from the list. See lib/widget_list/widgets.rb `default='info'`
278
+
279
+ `useBoxShadow` - Show shadow or not on list `default=true`
280
+
281
+ `shadowInset` - Number or string with '11Px' for an 11PX Inset `default=10`
282
+
283
+ `shadowSpread` - Number or string with '11Px' for an 11PX spread `default=20`
284
+
285
+ `shadowColor` - Color of bottom right shadow `default='shadowColor'`
286
+
287
+ `rowClass` - Class added to all rows `default=''`
288
+
289
+ `rowFontColor` - Font color of all data rows that dont have a rowStylesByStatus color: passed to it `default='black'`
290
+
291
+ `rowColorByStatus` - {'rowColorByStatus' =>
292
+ {'active'=>
293
+ {'No' => '#EBEBEB' }
294
+ }
295
+ }
296
+ Color a row based on the value of the column.
297
+ `default={}`
298
+
299
+ `rowStylesByStatus` - {'rowStylesByStatus' =>
300
+ {'active'=>
301
+ {'No' => 'font-style:italic;color:red;' }
302
+ }
303
+ }
304
+ Style a row based on the value of the column.
305
+ `default={}`
306
+
307
+ `rowOffsets` - Color for each row and offset `default=['FFFFFF','FFFFFF']`
308
+
309
+ `noDataMessage` - Message to show when no data is found `default='Currently no data.'`
310
+
311
+ `useSort` - Allow sorting on list `default=true`
312
+
313
+ `headerClass` - Class of each individual header column `default={}`
314
+
315
+ `fieldFunction` - A way to wrap or inject columns or SQL formatting in place of your columns `default={}`
316
+
317
+ `template` - Pass in a custom template for outer shell `default=''`
318
+
319
+ `templateFilter` - Instead of widget list building your search box. Pass your own HTML `default=''`
320
+
321
+ `storeSessionChecks` - See http://stackoverflow.com/questions/1928204/marshal-data-too-short for configuring larger session storage which checkboxes would eat up if you had this set to true `default=false`
322
+
323
+ `columnHooks` - Todo `default={}`
324
+
325
+ `rowHooks` - Todo `default={}`
326
+
327
+
328
+ ### #1 - Add widget_list CSS and JS to your application css and js
329
+
330
+ Change application.css to:
331
+ ```ruby
332
+ *= require widget_list
333
+ *= require widgets
334
+ ```
335
+ Change application.js to:
336
+ ```ruby
337
+ //= require widget_list
338
+ ```
339
+ ### #2 - Run `bundle exec rails s` to have widget_list create config/widget-list.yml (by default a sqlite3 memory database is created)
340
+
341
+ Configure your connection settings for your primary or secondary widget_list connections.
342
+
343
+ http://sequel.rubyforge.org/rdoc/files/doc/opening_databases_rdoc.html
344
+
345
+ ### #3 - If you wish to integrate into an existing rails application create a new controller
346
+
347
+ rails generate controller WidgetListExamples ruby_items
348
+
349
+ Then modify app/views/widget_list_examples/ruby_items.html.erb and add
350
+ ```ruby
351
+ <div style="margin:50px;">
352
+ <%=raw @output%>
353
+ </div>
354
+ ```
355
+ Add config/routes.rb if it is not in there:
356
+ ```ruby
357
+ match ':controller(/:action)'
358
+ ```
359
+ Ensure that sessions are loaded into active record because widget_list keeps track of several settings on each list for each session
360
+ ```ruby
361
+ config.session_store :active_record_store
362
+ ```
363
+ Add the example shown below to app/controllers/widget_list_examples_controller.rb#ruby_items
364
+
365
+ Go To http://localhost:3000/widget_list_examples/ruby_items
366
+
367
+ ****
368
+
369
+ ### Example Calling Page That Sets up Config and calls WidgetList.render
370
+
371
+ ****
372
+
373
+ ```ruby
374
+ #
375
+ # Load Sample "items" Data. Comment out in your first time executing a widgetlist to create the items table
376
+ #
377
+ =begin
378
+ begin
379
+ WidgetList::List.get_sequel.create_table :items do
380
+ primary_key :id
381
+ String :name
382
+ Float :price
383
+ Fixnum :sku
384
+ String :active
385
+ Date :date_added
386
+ end
387
+ items = WidgetList::List.get_sequel[:items]
388
+ 100.times {
389
+ items.insert(:name => 'ab\'c_quoted_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-01', :sku => rand(9999), :active => 'Yes')
390
+ items.insert(:name => '12"3_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-02', :sku => rand(9999), :active => 'Yes')
391
+ items.insert(:name => 'asdf_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-03', :sku => rand(9999), :active => 'Yes')
392
+ items.insert(:name => 'qwerty_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-04', :sku => rand(9999), :active => 'No')
393
+ items.insert(:name => 'meow_' + rand(35).to_s, :price => rand * 100, :date_added => '2008-02-05', :sku => rand(9999), :active => 'No')
394
+ }
395
+ rescue Exception => e
396
+ #
397
+ # Table already exists
398
+ #
399
+ logger.info "Test table in items already exists? " + e.to_s
400
+ end
401
+ =end
402
+
403
+ begin
404
+
405
+ list_parms = WidgetList::List::init_config()
406
+
407
+ #
408
+ # Give it a name, some SQL to feed widget_list and set a noDataMessage
409
+ #
410
+ list_parms['name'] = 'ruby_items_yum'
411
+
412
+ #
413
+ # Handle Dynamic Filters
414
+ #
415
+ groupBy = WidgetList::List::get_group_by_selection(list_parms)
416
+
417
+ case groupBy
418
+ when 'Item Name'
419
+ groupByFilter = 'item'
420
+ countSQL = 'COUNT(1) as cnt,'
421
+ groupBySQL = 'GROUP BY name'
422
+ groupByDesc = ' (Grouped By Name)'
423
+ when 'Sku Number'
424
+ groupByFilter = 'sku'
425
+ countSQL = 'COUNT(1) as cnt,'
426
+ groupBySQL = 'GROUP BY sku'
427
+ groupByDesc = ' (Grouped By Sku Number)'
428
+ else
429
+ groupByFilter = 'none'
430
+ countSQL = ''
431
+ groupBySQL = ''
432
+ groupByDesc = ''
433
+ end
434
+
435
+ list_parms['filter'] = []
436
+ list_parms['bindVars'] = []
437
+ drillDown, filterValue = WidgetList::List::get_filter_and_drilldown(list_parms['name'])
438
+
439
+ case drillDown
440
+ when 'filter_by_name'
441
+ list_parms['filter'] << " name = ? "
442
+ list_parms['bindVars'] << filterValue
443
+ list_parms['listDescription'] = WidgetList::List::drill_down_back(list_parms['name']) + ' Filtered by Name (' + filterValue + ')' + groupByDesc
444
+ when 'filter_by_sku'
445
+ list_parms['filter'] << " sku = ? "
446
+ list_parms['bindVars'] << filterValue
447
+ list_parms['listDescription'] = WidgetList::List::drill_down_back(list_parms['name']) + ' Filtered by SKU (' + filterValue + ')' + groupByDesc
448
+ else
449
+ list_parms['listDescription'] = ''
450
+ list_parms['listDescription'] = WidgetList::List::drill_down_back(list_parms['name']) if !groupByDesc.empty?
451
+ list_parms['listDescription'] += 'Showing All Ruby Items' + groupByDesc
452
+ end
453
+
454
+ # put <%= @output %> inside your view for initial load nothing to do here other than any custom concatenation of multiple lists
455
+ #
456
+ # Setup your first widget_list
457
+ #
458
+
459
+ button_column_name = 'actions'
460
+
461
+ #
462
+ # customFooter will add buttons to the bottom of the list.
463
+ #
464
+
465
+ list_parms['customFooter'] = WidgetList::Widgets::widget_button('Add New Item', {'page' => '/add/'} ) + WidgetList::Widgets::widget_button('Do something else', {'page' => '/else/'} )
466
+
467
+ #
468
+ # Give some SQL to feed widget_list and set a noDataMessage
469
+ #
470
+ list_parms['searchIdCol'] = ['id','sku']
471
+
472
+ #
473
+ # Because sku_linked column is being used and the raw SKU is hidden, we need to make this available for searching via fields_hidden
474
+ #
475
+ list_parms['fieldsHidden'] = ['sku']
476
+
477
+ drill_downs = []
478
+
479
+ drill_downs << WidgetList::List::build_drill_down( :list_id => list_parms['name'],
480
+ :drill_down_name => 'filter_by_name',
481
+ :data_to_pass_from_view => 'a.name',
482
+ :column_to_show => 'a.name',
483
+ :column_alias => 'name_linked'
484
+ )
485
+
486
+ drill_downs << WidgetList::List::build_drill_down(
487
+ :list_id => list_parms['name'],
488
+ :drill_down_name => 'filter_by_sku',
489
+ :data_to_pass_from_view => 'a.sku',
490
+ :column_to_show => 'a.sku',
491
+ :column_alias => 'sku_linked'
492
+ )
493
+
494
+ list_parms['view'] = '(
495
+ SELECT
496
+ ' + countSQL + '
497
+ ' + drill_downs.join(' , ') + ',
498
+ \'\' AS checkbox,
499
+ a.id AS id,
500
+ a.active AS active,
501
+ a.name AS name,
502
+ a.sku AS sku,
503
+ a.price AS price,
504
+ a.date_added AS date_added
505
+ FROM
506
+ items a
507
+ ' + groupBySQL + '
508
+ ) a'
509
+
510
+ #
511
+ # Map out the visible fields
512
+ #
513
+ list_parms['fields'] = {}
514
+ list_parms['fields']['checkbox'] = 'checkbox_header'
515
+ list_parms['fields']['cnt'] = 'Total Items In Group' if groupByFilter != 'none'
516
+ list_parms['fields']['id'] = 'Item Id' if groupByFilter == 'none'
517
+ list_parms['fields']['name_linked'] = 'Name' if groupByFilter == 'none' or groupByFilter == 'item'
518
+ list_parms['fields']['price'] = 'Price of Item' if groupByFilter == 'none'
519
+ list_parms['fields']['sku_linked'] = 'Sku #' if groupByFilter == 'none' or groupByFilter == 'sku'
520
+ list_parms['fields']['date_added'] = 'Date Added' if groupByFilter == 'none'
521
+ list_parms['fields']['active'] = 'Active Item' if groupByFilter == 'none'
522
+ list_parms['fields'][button_column_name] = button_column_name.capitalize if groupByFilter == 'none'
523
+
524
+
525
+ list_parms['noDataMessage'] = 'No Ruby Items Found'
526
+ list_parms['title'] = 'Ruby Items Using Sequel!!!'
527
+
528
+ #
529
+ # Create small button array and pass to the buttons key
530
+ #
531
+
532
+ mini_buttons = {}
533
+ mini_buttons['button_edit'] = {'page' => '/edit',
534
+ 'text' => 'Edit',
535
+ 'function' => 'Redirect',
536
+ #pass tags to pull from each column when building the URL
537
+ 'tags' => {'my_key_name' => 'name','value_from_database'=>'price'}}
538
+
539
+ mini_buttons['button_delete'] = {'page' => '/delete',
540
+ 'text' => 'Delete',
541
+ 'function' => 'alert',
542
+ 'innerClass' => 'danger'}
543
+ list_parms['buttons'] = {button_column_name => mini_buttons}
544
+ list_parms['fieldFunction'] = {
545
+ button_column_name => "''",
546
+ 'date_added' => ['postgres','oracle'].include?(WidgetList::List::get_db_type) ? "TO_CHAR(date_added, 'MM/DD/YYYY')" : "date_added"
547
+ }
548
+
549
+ list_parms['groupByItems'] = ['All Records', 'Item Name', 'Sku Number']
550
+
551
+
552
+ #
553
+ # Setup a custom field for checkboxes stored into the session and reloaded when refresh occurs
554
+ #
555
+ list_parms = WidgetList::List.checkbox_helper(list_parms,'id')
556
+
557
+ #
558
+ # Generate a template for the DOWN ARROW for CUSTOM FILTER
559
+ #
560
+ input = {}
561
+
562
+ input['id'] = 'comments'
563
+ input['name'] = 'comments'
564
+ input['width'] = '170'
565
+ input['max_length'] = '500'
566
+ input['input_class'] = 'info-input'
567
+ input['title'] = 'Optional CSV list'
568
+
569
+ button_search = {}
570
+ button_search['onclick'] = "alert('This would search, but is not coded. That is for you to do')"
571
+
572
+ list_parms['listSearchForm'] = WidgetList::Utils::fill( {
573
+ '<!--BUTTON_SEARCH-->' => WidgetList::Widgets::widget_button('Search', button_search),
574
+ '<!--COMMENTS-->' => WidgetList::Widgets::widget_input(input),
575
+ '<!--BUTTON_CLOSE-->' => "HideAdvancedSearch(this)" } ,
576
+ '
577
+ <div id="advanced-search-container">
578
+ <div class="widget-search-drilldown-close" onclick="<!--BUTTON_CLOSE-->">X</div>
579
+ <ul class="advanced-search-container-inline" id="search_columns">
580
+ <li>
581
+ <div>Search Comments</div>
582
+ <!--COMMENTS-->
583
+ </li>
584
+ </ul>
585
+ <br/>
586
+ <div style="text-align:right;width:100%;height:30px;" class="advanced-search-container-buttons"><!--BUTTON_RESET--><!--BUTTON_SEARCH--></div>
587
+ </div>'
588
+ # or to keep HTML out of controller render_to_string(:partial => 'partials/form_xxx')
589
+ )
590
+
591
+ #
592
+ # Control widths of special fields
593
+ #
594
+
595
+ list_parms['columnWidth'] = {
596
+ 'date_added'=>'200px',
597
+ 'sku_linked'=>'20px',
598
+ }
599
+
600
+ #
601
+ # If certain statuses of records are shown, visualize
602
+ #
603
+
604
+ list_parms.deep_merge!({'rowStylesByStatus' =>
605
+ {'active'=>
606
+ {'Yes' => '' }
607
+ }
608
+ })
609
+ list_parms.deep_merge!({'rowStylesByStatus' =>
610
+ {'active'=>
611
+ {'No' => 'font-style:italic;color:red;' }
612
+ }
613
+ })
614
+
615
+ list_parms.deep_merge!({'rowColorByStatus' =>
616
+ {'active'=>
617
+ {'Yes' => '' }
618
+ }
619
+ })
620
+ list_parms.deep_merge!({'rowColorByStatus' =>
621
+ {'active'=>
622
+ {'No' => '#EBEBEB' }
623
+ }
624
+ })
625
+
626
+
627
+ list_parms['columnPopupTitle'] = {}
628
+ list_parms['columnPopupTitle']['checkbox'] = 'Select any record'
629
+ list_parms['columnPopupTitle']['cnt'] = 'Total Count'
630
+ list_parms['columnPopupTitle']['id'] = 'The primary key of the item'
631
+ list_parms['columnPopupTitle']['name_linked'] = 'Name (Click to drill down)'
632
+ list_parms['columnPopupTitle']['price'] = 'Price of item (not formatted)'
633
+ list_parms['columnPopupTitle']['sku_linked'] = 'Sku # (Click to drill down)'
634
+ list_parms['columnPopupTitle']['date_added'] = 'The date the item was added to the database'
635
+ list_parms['columnPopupTitle']['active'] = 'Is the item active?'
636
+
637
+ output_type, output = WidgetList::List.build_list(list_parms)
638
+
639
+ case output_type
640
+ when 'html'
641
+ # put <%= @output %> inside your view for initial load nothing to do here other than any custom concatenation of multiple lists
642
+ @output = output
643
+ when 'json'
644
+ return render :inline => output
645
+ when 'export'
646
+ send_data(output, :filename => list_parms['name'] + '.csv')
647
+ return
648
+ end
649
+
650
+ rescue Exception => e
651
+
652
+ Rails.logger.info e.to_s + "\n\n" + $!.backtrace.join("\n\n")
653
+
654
+ #really this block is just to catch initial ruby errors in setting up your list_parms
655
+ #I suggest taking out this rescue when going to production
656
+ output_type, output = WidgetList::List.build_list(list_parms)
657
+
658
+ case output_type
659
+ when 'html'
660
+ @output = output
661
+ when 'json'
662
+ return render :inline => output
663
+ when 'export'
664
+ send_data(output, :filename => list_parms['name'] + '.csv')
665
+ return
666
+ end
667
+
668
+ end
669
+ ```
670
+
671
+ ****
672
+
673
+ ## Contributing
674
+
675
+ ****
676
+
677
+ 1. Fork it
678
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
679
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
680
+ 4. Push to the branch (`git push origin my-new-feature`)
681
+ 5. Create new Pull Request
682
+
683
+
684
+ Meta
685
+ ----
686
+
687
+ * Gems: <https://rubygems.org/gems/widget_list>
688
+
689
+
690
+ Authors
691
+ -------
692
+
693
+ David Renne :: david_renne @ ya hoo - .com :: @phpnerd
694
+
695
+ License
696
+ -------
697
+
698
+ Copyright 2012 David Renne
699
+
700
+ Licensed under the Apache License, Version 2.0 (the "License");
701
+ you may not use this file except in compliance with the License.
702
+ You may obtain a copy of the License at
703
+
704
+ http://www.apache.org/licenses/LICENSE-2.0
705
+
706
+ Unless required by applicable law or agreed to in writing, software
707
+ distributed under the License is distributed on an "AS IS" BASIS,
708
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
709
+ See the License for the specific language governing permissions and
710
+ limitations under the License.
711
+
712
+ [1]: https://github.com/davidrenne/widget_list_example/blob/master/app/helpers/widget_list_helper.rb
674
713
  [2]: https://github.com/davidrenne/widget_list_theme_blue_sky_basin