widget_list 1.0.0

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/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in widget_list.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +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
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,260 @@
1
+ widget_list
2
+ ====================
3
+ # WidgetList
4
+
5
+ ## Introduction
6
+
7
+ This is my first gem ever!
8
+
9
+ 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.
10
+
11
+ 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:
12
+
13
+ * A sleek ajaxified list
14
+ * Full sorting
15
+ * Search bar/Ajax searching
16
+ * Column mappings
17
+ * Buttons for each row and areas on the bottom of the grid where you can add "Action buttons" like Add R
18
+
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ gem 'widget_list'
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install widget_list
33
+
34
+ ## Usage
35
+
36
+ ### #1 - Add widget_list CSS and JS to your application css and js
37
+
38
+ Change application.css to:
39
+
40
+ *= require widget_list
41
+ *= require widgets
42
+
43
+ Change application.js to:
44
+
45
+ //= require widget_list
46
+
47
+ ### #2 - Run bundle exec rails s to have widget_list create config/widget-list.yml
48
+
49
+ Change application.css to:
50
+
51
+ *= require widget_list
52
+ *= require widgets
53
+
54
+ Change application.js to:
55
+
56
+ //= require widget_list
57
+
58
+ ### Example Calling Page That Sets up Config and calls WidgetList.render
59
+
60
+ #
61
+ # Load Sample "items" Data. Comment out in your first time executing a widgetlist to create the items table
62
+ #
63
+
64
+ # no table - create it and load it with 5K records
65
+ WidgetList::List.get_database.create_table :items do
66
+ primary_key :id
67
+ String :name
68
+ Float :price
69
+ end
70
+ items = WidgetList::List.get_database[:items]
71
+ 100.times {
72
+ items.insert(:name => 'abc', :price => rand * 100)
73
+ items.insert(:name => '123', :price => rand * 100)
74
+ items.insert(:name => 'asdf', :price => rand * 100)
75
+ items.insert(:name => 'qwerty', :price => rand * 100)
76
+ items.insert(:name => 'poop', :price => rand * 100)
77
+ }
78
+
79
+
80
+ #
81
+ # Setup your first widget_list
82
+ #
83
+
84
+ button_column_name = 'actions'
85
+ list_parms = {}
86
+
87
+ #
88
+ # action_buttons will add buttons to the bottom of the list.
89
+ #
90
+
91
+ action_buttons = WidgetList::Widgets::widget_button('Add New Item', {'page' => '/add/'} ) + WidgetList::Widgets::widget_button('Do something else', {'page' => '/else/'} )
92
+
93
+ #
94
+ # Give it a name, some SQL to feed widget_list and set a noDataMessage
95
+ #
96
+ list_parms['name'] = 'ruby_items_yum'
97
+ list_parms['view'] = '(SELECT \'\' as checkbox,a.* FROM items a ) a'
98
+ list_parms['noDataMessage'] = 'No Tables Found'
99
+ list_parms['title'] = 'Ruby Items!!!'
100
+
101
+ #
102
+ # Create small button array and pass to the buttons key
103
+ #
104
+
105
+ mini_buttons = {}
106
+ mini_buttons['button_edit'] = {'page' => '/edit',
107
+ 'text' => 'Edit',
108
+ 'function' => 'Redirect',
109
+ #pass tags to pull from each column when building the URL
110
+ 'tags' => {'my_key_name' => 'name','value_from_database'=>'price'}}
111
+
112
+ mini_buttons['button_delete'] = {'page' => '/delete',
113
+ 'text' => 'Delete',
114
+ 'function' => 'alert',
115
+ 'innerClass' => 'danger'}
116
+ list_parms['buttons'] = {button_column_name => mini_buttons}
117
+ list_parms['function'] = {button_column_name => "'' " + button_column_name }
118
+ list_parms['groupByItems']= ['All Records','Another Grouping Item']
119
+
120
+ #
121
+ # Generate a template for the DOWN ARROW for CUSTOM FILTER
122
+ #
123
+
124
+ template = {}
125
+ input = {}
126
+
127
+ input['id'] = 'comments'
128
+ input['name'] = 'comments'
129
+ input['width'] = '170'
130
+ input['max_length'] = '500'
131
+ input['input_class'] = 'info-input'
132
+ input['title'] = 'Optional CSV list'
133
+
134
+ button_search = {}
135
+ button_search['innerClass'] = "success btn-submit"
136
+ button_search['onclick'] = "alert('This would search, but is not coded. That is for you to do')"
137
+
138
+ list_parms['list_search_form'] = WidgetList::Utils::fill( {
139
+ '<!--COMMENTS-->' => WidgetList::Widgets::widget_input(input),
140
+ '<!--BUTTON_SEARCH-->' => WidgetList::Widgets::widget_button('Search', button_search),
141
+ '<!--BUTTON_CLOSE-->' => "HideAdvancedSearch(this)" } ,
142
+ '
143
+ <div id="advanced-search-container">
144
+ <div class="widget-search-drilldown-close" onclick="<!--BUTTON_CLOSE-->">X</div>
145
+ <ul class="advanced-search-container-inline" id="search_columns">
146
+ <li>
147
+ <div>Search Comments</div>
148
+ <!--COMMENTS-->
149
+ </li>
150
+ </ul>
151
+ <br/>
152
+ <div style="text-align:right;width:100%;height:30px;" class="advanced-search-container-buttons"><!--BUTTON_RESET--><!--BUTTON_SEARCH--></div>
153
+ </div>')
154
+
155
+ #
156
+ # Setup a custom field for checkboxes stored into the session and reloaded when refresh occurs
157
+ #
158
+
159
+ list_parms.deep_merge!({'fields' =>
160
+ {
161
+ 'checkbox'=> 'checkbox_header',
162
+ 'id'=> 'Item Id',
163
+ 'name'=> 'Name',
164
+ 'price'=> 'Price of Item',
165
+ button_column_name => button_column_name.capitalize,
166
+ }
167
+ })
168
+
169
+ list_parms.deep_merge!({'inputs' =>
170
+ {'checkbox'=>
171
+ {'type' => 'checkbox'
172
+ }
173
+ }
174
+ })
175
+
176
+ list_parms.deep_merge!({'inputs' =>
177
+ {'checkbox'=>
178
+ {'items' =>
179
+ {
180
+ 'name' => 'visible_checks[]',
181
+ 'value' => 'id', #the value should be a column name mapping
182
+ 'class_handle' => 'info_tables',
183
+ }
184
+ }
185
+ }
186
+ })
187
+
188
+ list_parms.deep_merge!({'inputs' =>
189
+ {'checkbox_header'=>
190
+ {'type' => 'checkbox'
191
+ }
192
+ }
193
+ })
194
+
195
+ list_parms.deep_merge!({'inputs' =>
196
+ {'checkbox_header'=>
197
+ {'items' =>
198
+ {
199
+ 'check_all' => true,
200
+ 'id' => 'info_tables_check_all',
201
+ 'class_handle' => 'info_tables',
202
+ }
203
+ }
204
+ }
205
+ })
206
+
207
+ list = WidgetList::List.new(list_parms)
208
+
209
+ #
210
+ # If AJAX, send back JSON
211
+ #
212
+ if $_REQUEST.key?('BUTTON_VALUE') && $_REQUEST['LIST_NAME'] == list_parms['name']
213
+ ret = {}
214
+ ret['list'] = WidgetList::Utils::fill({ '<!--CUSTOM_CONTENT-->' => action_buttons } , list.render() )
215
+ ret['list_id'] = list_parms['name']
216
+ ret['callback'] = 'ListSearchAheadResponse'
217
+ return render :inline => WidgetList::Utils::json_encode(ret)
218
+ else
219
+ #
220
+ # Else assign to variable for view
221
+ #
222
+ @output = WidgetList::Utils::fill({ '<!--CUSTOM_CONTENT-->' => action_buttons } , list.render() )
223
+ end
224
+
225
+ ## Contributing
226
+
227
+ 1. Fork it
228
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
229
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
230
+ 4. Push to the branch (`git push origin my-new-feature`)
231
+ 5. Create new Pull Request
232
+
233
+
234
+ Meta
235
+ ----
236
+
237
+ * Gems: <http://rubygems.org/gems/widget-list>
238
+
239
+
240
+ Authors
241
+ -------
242
+
243
+ David Renne :: david_renne @ ya hoo - .com :: @phpnerd
244
+
245
+ License
246
+ -------
247
+
248
+ Copyright 2012 David Renne
249
+
250
+ Licensed under the Apache License, Version 2.0 (the "License");
251
+ you may not use this file except in compliance with the License.
252
+ You may obtain a copy of the License at
253
+
254
+ http://www.apache.org/licenses/LICENSE-2.0
255
+
256
+ Unless required by applicable law or agreed to in writing, software
257
+ distributed under the License is distributed on an "AS IS" BASIS,
258
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
259
+ See the License for the specific language governing permissions and
260
+ limitations under the License.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,2054 @@
1
+ require 'widget_list/sequel'
2
+ require 'widget_list/version'
3
+ require 'widget_list/hash'
4
+ require 'widget_list/string'
5
+ require 'widget_list/utils'
6
+ require 'widget_list/tpl'
7
+ require 'widget_list/widgets'
8
+ require 'widget_list/railtie'
9
+ require 'json'
10
+ require 'uri'
11
+ require 'extensions/action_controller_base'
12
+ require 'sequel'
13
+
14
+
15
+ module WidgetList
16
+
17
+ if defined?(Rails) && defined?(Rails::Engine)
18
+ class Engine < ::Rails::Engine
19
+ require 'widget_list/engine'
20
+ end
21
+ end
22
+
23
+ class List
24
+
25
+ @debug = true
26
+
27
+ include ActionView::Helpers::SanitizeHelper
28
+
29
+ def self.connect
30
+
31
+ if Rails.root.join("config", "widget-list.yml").file?
32
+ config = YAML.load(ERB.new(File.new(Rails.root.join("config", "widget-list.yml")).read).result)[Rails.env]
33
+ @primary_conn = config[:primary]
34
+ @secondary_conn = config[:secondary]
35
+ else
36
+ throw 'widget-list.yml not found'
37
+ end
38
+
39
+ $DATABASE = Sequel.connect(@primary_conn) if @primary_conn.class.name == 'String'
40
+ $DATABASE2 = Sequel.connect(@secondary_conn) if @secondary_conn.class.name == 'String'
41
+
42
+ end
43
+
44
+ def self.get_database
45
+ case $current_db_selection
46
+ when 'primary'
47
+ $DATABASE
48
+ when 'secondary'
49
+ $DATABASE2
50
+ else
51
+ $DATABASE
52
+ end
53
+ end
54
+
55
+ # @param [Hash] list
56
+ def initialize(list={})
57
+
58
+ @items = {
59
+ 'name' => ([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(16).join,
60
+ 'database' => 'primary',
61
+ 'title' => '',# will add <h1> title and horizontal rule
62
+ 'listDescription' => '',# will add grey header box
63
+ 'pageId' => $_SERVER['PATH_INFO'],
64
+ 'sql' => '',
65
+ 'table' => '',
66
+ 'view' => '',
67
+ 'data' => {},
68
+ 'mode' => 'passive',
69
+ 'collClass' => '',
70
+ 'collAlign' => '',
71
+ 'fields' => {},
72
+ 'columns' => {},
73
+ 'bindVars' => [],
74
+ 'bindVarsLegacy' => {},
75
+ 'links' => {},
76
+ 'results' => {},
77
+ 'buttons' => {},
78
+ 'inputs' => {},
79
+ 'filter' => '',
80
+ 'rowStart' => 0,
81
+ 'rowLimit' => 10,
82
+ 'orderBy' => '',
83
+ 'allowHTML' => true,
84
+ 'strlength' => 30,
85
+ 'searchClear' => false, # build a custom conditional for each page to clear session
86
+ 'searchClearAll' => false, # build a custom conditional for each page to clear session
87
+ 'showPagination' => true,
88
+ 'searchSession' => true, #on list render use last filter
89
+
90
+ #
91
+ # Custom count query
92
+ #
93
+ 'force_count_sql' => '',
94
+ 'force_query_sql' => '',
95
+
96
+ #
97
+ # Counts
98
+ #
99
+ 'count_cache_time' => 180, #
100
+ 'cachedCount' => -1, #pass the count
101
+
102
+ #
103
+ # Ajax
104
+ #
105
+ 'ajax_action' => '',
106
+ 'ajax_function' => 'ListJumpMin',
107
+ 'ajax_search_function'=> 'ListJumpMin',
108
+
109
+ #
110
+ # Search
111
+ #
112
+ 'showSearch' => true,
113
+ 'searchOnkeyup' => '',
114
+ 'searchOnclick' => '',
115
+ 'searchIdCol' => 'id', #By default `id` column is here because typically if you call your PK's id and are auto-increment
116
+ 'searchInputLegacyCSS'=> false,
117
+ 'searchBtnName' => 'Search by Id or a list of Ids and more',
118
+ 'searchTitle' => '',
119
+ 'searchFieldsIn' => {}, #White list of fields to include in a alpha-numeric based search
120
+ 'searchFieldsOut' => {'id'=>true}, #Black list of fields to include in a alpha-numeric based search (default `id` to NEVER search when alpha seach)
121
+
122
+
123
+ #
124
+ # Group By Box
125
+ #
126
+ 'groupByItems' => [], #array of strings (each a new "select option")
127
+ 'groupBySelected' => false, #initially selected grouping - defaults to first in list if not
128
+ 'groupByLabel' => 'Group By',
129
+
130
+
131
+ #
132
+ # Advanced searching
133
+ #
134
+ 'list_search_form' => '', #The HTML form used for the advanced search drop down
135
+ 'list_search_attribs' => {}, #widgetinput "search_ahead" attributes
136
+
137
+ #
138
+ # Column Specific
139
+ #
140
+ 'columnStyle' => {},
141
+ 'columnClass' => {},
142
+ 'columnPopupTitle' => {},
143
+ 'columnSort' => {},
144
+ 'columnWidth' => {},
145
+ 'columnNoSort' => {},
146
+ 'columnFilter' => {},
147
+
148
+ #
149
+ # Row specifics
150
+ #
151
+ 'rowColor' => '#FFFFFF',
152
+ 'rowClass' => '',
153
+ 'rowColorByStatus' => {},
154
+ 'rowStylesByStatus' => {},
155
+ 'offsetRows' => true,
156
+ 'rowOffsets' => ['FFFFFF','FFFFFF'],
157
+
158
+ 'class' => 'listContainerPassive',
159
+ 'tableclass' => '',
160
+ 'noDataMessage' => 'Currently no data.',
161
+ 'useSort' => true,
162
+ 'headerClass' => {},
163
+ 'groupBy' => '',
164
+ 'function' => {},
165
+ 'buttonVal' => 'templateListJump',
166
+ 'linkFunction' => 'ButtonLinkPost',
167
+ 'template' => '',
168
+ 'templateFilter' => '',
169
+ 'pagerFull' => true,
170
+ 'LIST_COL_SORT_ORDER' => 'ASC',
171
+ 'LIST_COL_SORT' => '',
172
+ 'LIST_FILTER_ALL' => '',
173
+ 'ROW_LIMIT' => '',
174
+ 'LIST_SEQUENCE' => 1,
175
+ 'NEW_SEARCH' => false,
176
+
177
+ #
178
+ # Checkbox
179
+ #
180
+ 'checked_class' => 'widgetlist-checkbox',
181
+ 'checked_flag' => {},
182
+
183
+ #
184
+ # Hooks
185
+ #
186
+ 'column_hooks' => {},
187
+ 'row_hooks' => {}
188
+ }
189
+
190
+ @totalRowCount= 0
191
+ @totalPages = 0
192
+ @fixHtmlLinksReplace = {}
193
+
194
+ @sequence = 1
195
+ @totalRows = 0
196
+ @totalPage = 0
197
+ @listSortNext = 'ASC'
198
+ @filter = ''
199
+ @listFilter = ''
200
+ @fieldList = []
201
+ @templateFill = {}
202
+ @results = {}
203
+
204
+ @items.deep_merge!({'template' =>
205
+ '
206
+ <!--HEADER-->
207
+ <div class="<!--CLASS-->" id="<!--NAME-->">
208
+ <table class="list <!--TABLE_CLASS-->" style="<!--INLINE_STYLE-->" border="0" width="100%" cellpadding="0" cellspacing="0">
209
+ <!--LIST_TITLE-->
210
+ <tr class="list_header"><!--HEADERS--></tr>
211
+ <!--DATA-->
212
+ <tr>
213
+ <td colspan="<!--COLSPAN_FULL-->" align="left" style="padding:0px;margin:0px;text-align:left">
214
+ <div style="background-color:#ECECEC;height:50px;"><div style="padding:10px"><!--CUSTOM_CONTENT--></div>
215
+ </td>
216
+ </tr>
217
+ </table>
218
+ <div class="pagination" style="float:left;text-align:left;width:100%;margin:0px;padding:0px;"><div style="margin:auto;float:left;margin:0px;padding:0px;"><!--PAGINATION_LIST--></div></div>
219
+ <!--FILTER-->
220
+ <input type="hidden" name="<!--JUMP_URL_NAME-->" id="<!--JUMP_URL_NAME-->" value="<!--JUMP_URL-->">
221
+ </div>
222
+ '
223
+ })
224
+
225
+ @items.deep_merge!({'row' =>
226
+ '
227
+ <tr style="background-color:<!--BGCOLOR-->;<!--ROWSTYLE-->" class="<!--ROWCLASS-->"><!--CONTENT--></tr>
228
+ '
229
+ })
230
+
231
+ @items.deep_merge!({'list_description' =>
232
+ '
233
+ <tr class="summary">
234
+ <td id="<!--LIST_NAME-->_list_description" class="header" style="text-align:left;padding-bottom:5px;padding-top:5px;" colspan="<!--COLSPAN-->"><!--LIST_DESCRIPTION--></td>
235
+ </tr>
236
+ '
237
+ })
238
+
239
+ @items.deep_merge!({'col' =>
240
+ '
241
+ <td class="<!--CLASS-->" align="<!--ALIGN-->" title="<!--TITLE-->" onclick="<!--ONCLICK-->" style="<!--STYLE-->"><!--CONTENT--></td>
242
+ '
243
+ })
244
+
245
+ @items.deep_merge!({'templateSequence' =>
246
+ '
247
+ <!--LIST_SEQUENCE--> of <!--TOTAL_PAGES-->
248
+ '
249
+ })
250
+ #Sorting
251
+ #
252
+ @items.deep_merge!({'templateSortColumn' =>
253
+ '
254
+ <td style="font-weight:bold;<!--INLINE_STYLE-->" id="<!--COL_HEADER_ID-->" class="<!--COL_HEADER_CLASS-->" valign="middle"><span onclick="<!--FUNCTION-->(\'<!--COLSORTURL-->\',\'<!--NAME-->\')" style="cursor:pointer;background:none;" title="<!--TITLE_POPUP-->"><!--TITLE--><!--COLSORTICON-></span></td>
255
+ '
256
+ })
257
+
258
+ @items.deep_merge!({'templateNoSortColumn' =>
259
+ '
260
+ <td style="font-weight:bold;<!--INLINE_STYLE-->" title="<!--TITLE_POPUP-->" id="<!--COL_HEADER_ID-->" class="<!--COL_HEADER_CLASS-->" valign="middle"><span style="background:none;"><!--TITLE--></span></td>
261
+ '
262
+ })
263
+
264
+ @items.deep_merge!({'statement' =>
265
+ {'select'=>
266
+ {'view' =>
267
+ '
268
+ SELECT <!--FIELDS--> FROM <!--SOURCE--> <!--WHERE--> <!--GROUPBY--> <!--ORDERBY--> <!--LIMIT-->
269
+ '
270
+ }
271
+ }
272
+ })
273
+
274
+ @items.deep_merge!({'statement' =>
275
+ {'select'=>
276
+ {'sql' =>
277
+ '
278
+ SELECT <!--FIELDS--> FROM (<!--SQL-->) a <!--WHERE--> <!--GROUPBY--> <!--ORDERBY--> <!--LIMIT-->
279
+ '
280
+ }
281
+ }
282
+ })
283
+
284
+ @items.deep_merge!({'statement' =>
285
+ {'count'=>
286
+ {'view' =>
287
+ '
288
+ SELECT count(1) total FROM <!--VIEW--> <!--WHERE-->
289
+ '
290
+ }
291
+ }
292
+ })
293
+
294
+ @items.deep_merge!({'statement' =>
295
+ {'count'=>
296
+ {'sql' =>
297
+ '
298
+ SELECT count(1) total FROM (<!--SQL-->) s <!--WHERE-->
299
+ '
300
+ }
301
+ }
302
+ })
303
+
304
+ @items.deep_merge!({'statement' =>
305
+ {'count'=>
306
+ {'table' =>
307
+ '
308
+ SELECT count(1) total FROM <!--TABLE--> <!--WHERE-->
309
+ '
310
+ }
311
+ }
312
+ })
313
+
314
+ #Pagintion
315
+ #
316
+
317
+ @items.deep_merge!({'template_pagination_wrapper' =>
318
+ '
319
+ <ul id="pagination" class="page_legacy">
320
+ Page <!--PREVIOUS_BUTTON-->
321
+ <input type="text" value="<!--SEQUENCE-->" size="1" style="width:15px;padding:0px;font-size:10px;">
322
+ <input type="hidden" id="<!--LIST_NAME-->_total_rows" value="<!--TOTAL_ROWS-->">
323
+ <!--NEXT_BUTTON--> of <!--TOTAL_PAGES--> pages <span style="margin-left:20px">Total <!--TOTAL_ROWS--> records found</span>
324
+ <span style="padding-left:20px;">Show <!--PAGE_SEQUENCE_JUMP_LIST--> per page</span>
325
+ </ul>
326
+ '
327
+ })
328
+
329
+ @items.deep_merge!({'template_pagination_next_active' =>
330
+ "
331
+ <li><span onclick=\"<!--FUNCTION-->('<!--NEXT_URL-->','<!--LIST_NAME-->')\" style=\"cursor:pointer;background: transparent url(<!--HTTP_SERVER-->images/page-next.gif) no-repeat\">&nbsp;</span></li>
332
+ "
333
+ })
334
+
335
+ @items.deep_merge!({'template_pagination_next_disabled' =>
336
+ "
337
+ <li><span style=\"opacity:0.4;filter:alpha(opacity=40);background: transparent url(<!--HTTP_SERVER-->images/page-next.gif) no-repeat\">&nbsp;</span></li>
338
+ "
339
+ })
340
+
341
+ @items.deep_merge!({'template_pagination_previous_active' =>
342
+ "
343
+ <li><span onclick=\"<!--FUNCTION-->('<!--PREVIOUS_URL-->','<!--LIST_NAME-->')\" style=\"cursor:pointer;background: transparent url(<!--HTTP_SERVER-->images/page-back.gif) no-repeat\">&nbsp;</span></li>
344
+ "
345
+ })
346
+
347
+ @items.deep_merge!({'template_pagination_previous_disabled' =>
348
+ "
349
+ <li><span style=\"opacity:0.4;filter:alpha(opacity=40);background: transparent url(<!--HTTP_SERVER-->images/page-back.gif) no-repeat\">&nbsp;</span></li>
350
+ "
351
+ })
352
+
353
+ @items.deep_merge!({'template_pagination_jump_active' =>
354
+ '
355
+ <li><div class="active"><!--SEQUENCE--></div></li>
356
+ '
357
+ })
358
+
359
+ @items.deep_merge!({'template_pagination_jump_unactive' =>
360
+ '
361
+ <li onclick="<!--FUNCTION-->(\'<!--JUMP_URL-->\',\'<!--LIST_NAME-->\')"><div><!--SEQUENCE--></div></li>
362
+ '
363
+ })
364
+
365
+ @items = WidgetList::Widgets::populate_items(list,@items)
366
+
367
+
368
+ begin
369
+ @isJumpingList = false
370
+
371
+ #Ajax ListJump
372
+ if ! $_REQUEST.empty?
373
+ if $_REQUEST.key?('LIST_FILTER_ALL')
374
+ @items['LIST_FILTER_ALL'] = $_REQUEST['LIST_FILTER_ALL']
375
+ @isJumpingList = true
376
+ end
377
+
378
+ if $_REQUEST.key?('LIST_COL_SORT')
379
+ @items['LIST_COL_SORT'] = $_REQUEST['LIST_COL_SORT']
380
+ @isJumpingList = true
381
+ end
382
+
383
+ if $_REQUEST.key?('LIST_COL_SORT_ORDER')
384
+ @items['LIST_COL_SORT_ORDER'] = $_REQUEST['LIST_COL_SORT_ORDER']
385
+ @isJumpingList = true
386
+ end
387
+
388
+ if $_REQUEST.key?('LIST_SEQUENCE')
389
+ @items['LIST_SEQUENCE'] = $_REQUEST['LIST_SEQUENCE'].to_i
390
+ @isJumpingList = true
391
+ end
392
+
393
+ if $_REQUEST.key?('ROW_LIMIT')
394
+ @items['ROW_LIMIT'] = $_REQUEST['ROW_LIMIT']
395
+ @isJumpingList = true
396
+
397
+ if @items['showPagination']
398
+ $_SESSION['pageDisplayLimit'] = $_REQUEST['ROW_LIMIT']
399
+ $_SESSION.deep_merge!({'ROW_LIMIT' => { @items['name'] => $_REQUEST['ROW_LIMIT']} })
400
+ end
401
+
402
+ end
403
+
404
+ clear_sort_get_vars()
405
+
406
+ if $_REQUEST.key?('list_action') && $_REQUEST['list_action'] == 'ajax_widgetlist_checks'
407
+ ajax_maintain_checks()
408
+ end
409
+
410
+ end
411
+
412
+ # current_db is a flag of the last known primary or secondary YML used or defaulted when running a list
413
+ $current_db_selection = @items['database']
414
+
415
+ @items['groupByClick'] = "ListChangeGrouping('" + @items['name'] + "')"
416
+
417
+ =begin
418
+ #todo
419
+ @items['fieldNames'] = {};
420
+ if (empty(@items['fields']) && empty(@items['data']))
421
+ {
422
+ #Lazy mode where new columns added to view show up in list (unless you name the column "HIDE_xxxxx")
423
+ #
424
+ if (@items['sql'])
425
+ {
426
+ preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", @items['sql'], $match);
427
+ $viewName = $match[1];
428
+ }
429
+ elseif (@items['view'])
430
+ {
431
+ $viewName = @items['view'];
432
+ }
433
+
434
+ if ($this->DATABASE->Select("SHOW FULL COLUMNS IN ".$viewName))
435
+ {
436
+ foreach($this->DATABASE->results['FIELD'] as $col)
437
+ {
438
+ @items['fieldNames'][] = $col;
439
+ $columnUpper = strtoupper($col);
440
+ $columnLower = strtolower($col);
441
+ if (substr($columnUpper,0,5) != 'HIDE_')
442
+ {
443
+ #any columns named HIDE_ will not show
444
+ #
445
+ @items['fields'][$columnLower] = $this->autoColumnName($columnUpper);
446
+ if ($columnLower != 'features')
447
+ {
448
+ @items['columnSort'][$columnLower] = $columnLower;
449
+ }
450
+ }
451
+ }
452
+ }
453
+ }
454
+ =end
455
+
456
+ if $_REQUEST.key?('searchClear')
457
+ clear_search_session()
458
+ end
459
+
460
+ if @items['searchClear'] || @items['searchClearAll']
461
+ clear_search_session(@items.key?('searchClearAll'))
462
+ end
463
+
464
+ matchesCurrentList = $_REQUEST.key?('BUTTON_VALUE') && $_REQUEST['BUTTON_VALUE'] == @items['buttonVal']
465
+ isSearchRequest = $_REQUEST.key?('search_filter')
466
+ templateCustomSearch = !@items['templateFilter'].empty? # if you define templateFilter WidgetList will not attempt to build a where clause with search
467
+
468
+ #
469
+ # Search restore
470
+ #
471
+ if !isSearchRequest && $_SESSION.key?('SEARCH_FILTER') && $_SESSION['SEARCH_FILTER'].key?(@items['name']) && @items['searchSession']
472
+ isSearchRestore = true
473
+ end
474
+
475
+ if (isSearchRequest && matchesCurrentList && !templateCustomSearch && @items['showSearch']) || isSearchRestore
476
+ if !isSearchRestore
477
+ $_SESSION.deep_merge!({'SEARCH_FILTER' => { @items['name'] => $_REQUEST['search_filter']} })
478
+ searchFilter = $_REQUEST['search_filter'].strip_or_self()
479
+ else
480
+ searchFilter = $_SESSION['SEARCH_FILTER'][@items['name']]
481
+ end
482
+
483
+ if ! searchFilter.empty?
484
+ if ! @items['filter'].empty? && @items['filter'].class.name != 'Array'
485
+ # convert string to array filter
486
+ filterString = @items['filter']
487
+ @items['filter'] = []
488
+ @items['filter'] << filterString
489
+ end
490
+
491
+ fieldsToSearch = @items['fields']
492
+
493
+ @items['columns'].each { |columnPivot|
494
+ fieldsToSearch[columnPivot] = columnPivot
495
+ }
496
+
497
+ searchCriteria = searchFilter.strip_or_self()
498
+ searchSQL = []
499
+ numericSearch = false
500
+
501
+ #
502
+ # Comma delimited search
503
+ #
504
+ if searchFilter.include?(',')
505
+ #It is either a CSV or a comma inside the search string
506
+ #
507
+ criteriaTmp = searchFilter.split_it(',')
508
+
509
+ #Assumed a CSV of numeric ids
510
+ #
511
+ isNumeric = true
512
+ criteriaTmp.each_with_index { |value, key|
513
+ if !value.empty?
514
+ criteriaTmp[key] = value.strip_or_self()
515
+
516
+ if !criteriaTmp[key].nil? && ! criteriaTmp[key].empty?
517
+ if ! WidgetList::Utils::numeric?(criteriaTmp[key])
518
+ isNumeric = false
519
+ end
520
+ else
521
+ criteriaTmp.delete(key)
522
+ end
523
+ end
524
+ }
525
+
526
+ if isNumeric
527
+ if @items['searchIdCol'].class.name == 'Array'
528
+ @items['searchIdCol'].each { |searchIdCol|
529
+ if(fieldsToSearch.key?(searchIdCol))
530
+ searchSQL << "`" + searchIdCol + "` IN(" + searchFilter + ")"
531
+ end
532
+ }
533
+
534
+ if !searchSQL.empty?
535
+ #
536
+ # Assemble Numeric Filter
537
+ #
538
+ @items['filter'] << "(" + searchSQL.join(' OR ') + ")"
539
+ end
540
+ elsif @items['fields'].key?(@items['searchIdCol'])
541
+ numericSearch = true
542
+ @items['filter'] << "`#{@items['searchIdCol']}` IN(" + criteriaTmp.join(',') + ")"
543
+ end
544
+ end
545
+ elsif @items['searchIdCol'].class.name == 'Array'
546
+ if WidgetList::Utils::numeric?(searchFilter) && ! searchFilter.include?('.')
547
+ @items['searchIdCol'].each { |searchIdCol|
548
+ if fieldsToSearch.key?(searchIdCol)
549
+ searchSQL << "`#{searchIdCol}` IN(#{searchFilter})"
550
+ end
551
+ }
552
+
553
+ if !searchSQL.empty?
554
+ #
555
+ # Assemble Numeric Filter
556
+ #
557
+ @items['filter'] << "(" + searchSQL.join(' OR ') + ")"
558
+ end
559
+ end
560
+ #elsif WidgetList::Utils::numeric?(searchFilter) && ! searchFilter.include?('.') && @items['fields'].key?(@items['searchIdCol'])
561
+ # #19.95 is numeric, but people might be searching for dollar amounts which should be string based search
562
+ # numericSearch = true
563
+ #
564
+ # @items['filter'] << "`#{@items['searchIdCol']}` IN(" + searchFilter + ")"
565
+ end
566
+
567
+ # If it is not an id or a list of ids then it is assumed a string search
568
+ if !numericSearch
569
+ ii = 0
570
+ fieldsToSearch.each { |fieldName,fieldTitle|
571
+
572
+ # new lodgette. if function exists, find all matches and skip them
573
+ skip = false
574
+ (@items['function']||{}).each { |k,v|
575
+ if fieldName == k
576
+ skip = true
577
+ end
578
+ }
579
+
580
+ #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)
581
+ if (!@items['buttons'].empty? && ii == (fieldsToSearch.length - 1)) || skip
582
+ next
583
+ end
584
+
585
+ #Search only specified fields. This can involve a dynamic field list from an advanced search form
586
+ #
587
+ if ! @items['searchFieldsIn'].empty?
588
+ #
589
+ # If it exists in either key or value
590
+ #
591
+ if ! @items['searchFieldsIn'].key?(fieldName) && ! @items['searchFieldsIn'].include?(fieldName)
592
+ next
593
+ end
594
+ elsif ! @items['searchFieldsOut'].empty?
595
+ if @items['searchFieldsOut'].key?(fieldName) || @items['searchFieldsOut'].include?(fieldName)
596
+ next
597
+ end
598
+ end
599
+
600
+ #todo - escape bind variables using Sequel
601
+ searchSQL << "`#{fieldName}` LIKE '%" + searchCriteria + "%'"
602
+ ii = ii + 1
603
+ }
604
+
605
+ #
606
+ # Assemble String Filter
607
+ #
608
+ if(! searchSQL.empty?)
609
+ @items['filter'] << "(" + searchSQL.join(' OR ') + ")"
610
+ end
611
+ end
612
+ end
613
+ end
614
+
615
+ if !$_REQUEST.key?('BUTTON_VALUE')
616
+
617
+ #Initialize page load/Session stuff whe list first loads
618
+ #
619
+ clear_check_box_session(@items['name'])
620
+ end
621
+
622
+
623
+ if ! @items.key?('templateHeader')
624
+ @items['templateHeader'] = ''
625
+ end
626
+
627
+ #Set a list title if it exists
628
+ #
629
+
630
+ if ! $_REQUEST.key?('BUTTON_VALUE') && !@items['title'].empty?
631
+ @items['templateHeader'] = '
632
+ <h1><!--TITLE--></h1><div class="horizontal_rule"></div>
633
+ <!--FILTER_HEADER-->
634
+ '
635
+ else
636
+ if !$_REQUEST.key?('BUTTON_VALUE')
637
+ # Only if not in ajax would we want to output the filter header
638
+ #
639
+ @items['templateHeader'] = '
640
+ <!--FILTER_HEADER-->
641
+ '
642
+ end
643
+ end
644
+
645
+ # Build the filter (If any)
646
+ #
647
+ # todo - unit test filter
648
+ if !@items['filter'].empty? && @items['filter'].class.name == 'Array'
649
+ @filter = @items['filter'].join(' AND ')
650
+ elsif !@items['filter'].empty? && @items['filter'].class.name == 'String'
651
+ @filter = @items['filter']
652
+ end
653
+
654
+ #Sorting
655
+ #
656
+
657
+ if !@items['LIST_COL_SORT'].empty?
658
+ @items['LIST_SEQUENCE'] = 1
659
+ end
660
+
661
+ if @items['LIST_SEQUENCE'].class.name == 'Fixnum' && @items['LIST_SEQUENCE'] > 0
662
+ @sequence = @items['LIST_SEQUENCE'].to_i
663
+ end
664
+
665
+ if ! @items['ROW_LIMIT'].empty?
666
+ @items['rowLimit'] = @items['ROW_LIMIT'].to_i
667
+ end
668
+
669
+ if $_SESSION.key?('ROW_LIMIT') && $_SESSION['ROW_LIMIT'].key?(@items['name']) && !$_SESSION['ROW_LIMIT'][@items['name']].empty?
670
+ @items['rowLimit'] = $_SESSION['ROW_LIMIT'][@items['name']].to_i
671
+ end
672
+
673
+ if ! @items['LIST_COL_SORT'].empty?
674
+ case @items['LIST_COL_SORT_ORDER']
675
+ when 'ASC'
676
+ @listSortNext = 'DESC'
677
+ else
678
+ @listSortNext = 'ASC'
679
+ end
680
+ end
681
+
682
+ generate_limits()
683
+ rescue Exception => e
684
+ @templateFill['<!--DATA-->'] = '<tr><td colspan="50"><div id="noListResults">' + generate_error_output(e) + @items['noDataMessage'] + '</div></td></tr>'
685
+ end
686
+ end
687
+
688
+ def ajax_maintain_checks()
689
+
690
+ #
691
+ # A list must be provided
692
+ #
693
+ if $_REQUEST.key?('LIST_NAME')
694
+ listName = $_REQUEST['LIST_NAME']
695
+ sqlHash = $_REQUEST['SQL_HASH']
696
+
697
+ #
698
+ # The placeholder is created when the list initially forms. This validates it and makes it so
699
+ # not just anything can be injected into the session via this method.
700
+ #
701
+
702
+ #
703
+ # For each posted check box
704
+ #
705
+
706
+ $_REQUEST.each { |value, checked|
707
+ if checked.to_s == '1'
708
+ #
709
+ # Set it as checked
710
+ #
711
+ $_SESSION.deep_merge!({'list_checks' => { listName + sqlHash + value => true } })
712
+ else
713
+ #
714
+ # Unset if it exists and is unchecked
715
+ #
716
+ if $_SESSION['list_checks'].key?(listName + sqlHash + value)
717
+ $_SESSION['list_checks'].delete(listName + sqlHash + value)
718
+ end
719
+ end
720
+ }
721
+
722
+ #
723
+ # Check All
724
+ #
725
+ if $_REQUEST.key?('checked_all')
726
+ if $_SESSION.key?('list_checks')
727
+
728
+ if $_SESSION['list_checks'].key?('check_all_' + sqlHash + $_REQUEST['LIST_NAME'] + $_REQUEST['LIST_SEQUENCE'])
729
+ if $_REQUEST['checked_all'].empty?
730
+ $_SESSION['list_checks'].delete('check_all_' + sqlHash + $_REQUEST['LIST_NAME'] + $_REQUEST['LIST_SEQUENCE'])
731
+ else
732
+ $_SESSION.deep_merge!({'list_checks' => { 'check_all_' + sqlHash + $_REQUEST['LIST_NAME'] + $_REQUEST['LIST_SEQUENCE'] => true } })
733
+ end
734
+ else
735
+ if ! $_REQUEST['checked_all'].empty?
736
+ $_SESSION.deep_merge!({'list_checks' => { 'check_all_' + sqlHash + $_REQUEST['LIST_NAME'] + $_REQUEST['LIST_SEQUENCE'] => true } })
737
+ end
738
+ end
739
+ end
740
+ end
741
+ end
742
+ end
743
+
744
+ def clear_check_box_session(name='')
745
+
746
+ if $_SESSION.key?('DRILL_DOWN_FILTERS')
747
+ $_SESSION.delete('DRILL_DOWN_FILTERS')
748
+ end
749
+
750
+ if $_SESSION.key?('DRILL_DOWNS')
751
+ $_SESSION.delete('DRILL_DOWNS')
752
+ end
753
+
754
+ end
755
+
756
+ def clear_search_session(all=false)
757
+
758
+ if $_SESSION.key?('SEARCH_FILTER') && $_SESSION['SEARCH_FILTER'].key?(@items['name'])
759
+ $_SESSION['SEARCH_FILTER'].delete(@items['name'])
760
+ end
761
+
762
+ if $_SESSION.key?('ROW_LIMIT') && $_SESSION['ROW_LIMIT'].key?(@items['name'])
763
+ $_SESSION['ROW_LIMIT'].delete(@items['name'])
764
+ end
765
+
766
+ if all && $_SESSION.key?('SEARCH_FILTER')
767
+ $_SESSION.delete('SEARCH_FILTER')
768
+ end
769
+
770
+ if all && $_SESSION.key?('ROW_LIMIT')
771
+ $_SESSION.delete('ROW_LIMIT')
772
+ end
773
+
774
+ end
775
+
776
+ def clear_sql_session(all=false)
777
+
778
+ if $_SESSION.key?('LIST_SEQUENCE') && $_SESSION['LIST_SEQUENCE'].key?(@sqlHash)
779
+ $_SESSION['LIST_SEQUENCE'].delete(@sqlHash)
780
+ end
781
+
782
+ if $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].key?(@sqlHash)
783
+ $_SESSION['LIST_COL_SORT'].delete(@sqlHash)
784
+ end
785
+
786
+ if all && $_SESSION.key?('LIST_COL_SORT')
787
+ $_SESSION.delete('LIST_COL_SORT')
788
+ end
789
+
790
+ if all && $_SESSION.key?('LIST_SEQUENCE')
791
+ $_SESSION.delete('LIST_SEQUENCE')
792
+ end
793
+
794
+ end
795
+
796
+ def clear_sort_get_vars()
797
+ $_REQUEST.delete('LIST_FILTER_ALL')
798
+ $_REQUEST.delete('ROW_LIMIT')
799
+ $_REQUEST.delete('LIST_SEQUENCE')
800
+ $_REQUEST.delete('LIST_COL_SORT_ORDER')
801
+ $_REQUEST.delete('LIST_COL_SORT')
802
+ $_REQUEST.delete('LIST_FILTER_ALL')
803
+ end
804
+
805
+ def generate_limits()
806
+ #Pagination
807
+ #
808
+ @items['bindVarsLegacy']['LOW'] = @items['rowStart']
809
+ @items['bindVarsLegacy']['HIGH'] = @items['rowLimit']
810
+
811
+ if @sequence.to_i > 1 && ! @items['NEW_SEARCH']
812
+ @items['bindVarsLegacy']['LOW'] = (((@sequence * @items['rowLimit']) - @items['rowLimit']))
813
+ end
814
+ end
815
+
816
+ # @param [Hash] results
817
+ # pass results of $DATABASE.final_results after running a _select query
818
+ def render(results={})
819
+
820
+ begin
821
+ if !results.empty?
822
+ @items['data'] = results
823
+ end
824
+
825
+ #Get total records for statement validation and pagination
826
+ #
827
+ @items['data'].keys.each { |column|
828
+ @items['fields'][column.downcase] = auto_column_name(column)
829
+ } if !@items['data'].empty? && @items['fields'].empty?
830
+
831
+ if @items['data'].empty?
832
+ # Generate count() from database
833
+ #
834
+ @totalResultCount = get_total_records()
835
+ else
836
+ # Count the items in the passed data
837
+ #
838
+ @items['data'].keys.each { |column|
839
+ @totalResultCount = @items['data'][column].count
840
+ @totalRowCount = @totalResultCount
841
+ @totalRows = @totalResultCount
842
+ break
843
+ }
844
+ end
845
+
846
+ build_rows()
847
+
848
+ build_headers()
849
+
850
+ listJumpUrl = {}
851
+ listJumpUrl['PAGE_ID'] = @items['pageId']
852
+ listJumpUrl['ACTION'] = 'AJAX'
853
+ listJumpUrl['BUTTON_VALUE'] = @items['buttonVal']
854
+ listJumpUrl['LIST_COL_SORT'] = @items['LIST_COL_SORT']
855
+ listJumpUrl['LIST_COL_SORT_ORDER'] = @items['LIST_COL_SORT_ORDER']
856
+ listJumpUrl['LIST_FILTER_ALL'] = @items['LIST_FILTER_ALL']
857
+ listJumpUrl['ROW_LIMIT'] = @items['ROW_LIMIT']
858
+ listJumpUrl['LIST_SEQUENCE'] = @sequence
859
+ listJumpUrl['LIST_NAME'] = @items['name']
860
+ listJumpUrl['SQL_HASH'] = @sqlHash
861
+
862
+ if @items.key?('ajax_action')
863
+ listJumpUrl['list_action'] = @items['ajax_action']
864
+ end
865
+
866
+ @templateFill['<!--HEADER-->'] = @items['templateHeader']
867
+ @templateFill['<!--TITLE-->'] = @items['title']
868
+ @templateFill['<!--NAME-->'] = @items['name']
869
+ @templateFill['<!--JUMP_URL-->'] = WidgetList::Utils::build_url(@items['pageId'],listJumpUrl,(!$_REQUEST.key?('BUTTON_VALUE')))
870
+ @templateFill['<!--JUMP_URL_NAME-->'] = @items['name'] + '_jump_url'
871
+ @templateFill['<!--CLASS-->'] = @items['class']
872
+
873
+ if @totalRowCount > 0
874
+ @templateFill['<!--INLINE_STYLE-->'] = ''
875
+ @templateFill['<!--TABLE_CLASS-->'] = @items['tableclass']
876
+ else
877
+ @templateFill['<!--INLINE_STYLE-->'] = 'table-layout:auto;'
878
+ end
879
+ #Filter form
880
+ #
881
+ if @items['showSearch'] === true
882
+ if ! @items['templateFilter'].empty?
883
+ @templateFill['<!--FILTER_HEADER-->'] = @items['templateFilter']
884
+ else
885
+ if !$_REQUEST.key?('search_filter') && !@isJumpingList
886
+
887
+ #Search page url
888
+ #
889
+ searchUrl = ''
890
+ searchVal = ''
891
+
892
+ if ! @items['buttonVal'].empty?
893
+ searchVal = @items['buttonVal']
894
+ else
895
+ searchVal = @items['name']
896
+ end
897
+
898
+ filterParameters = {}
899
+ filterParameters['BUTTON_VALUE'] = searchVal
900
+ filterParameters['PAGE_ID'] = @items['pageId']
901
+ filterParameters['LIST_NAME'] = @items['name']
902
+ filterParameters['SQL_HASH'] = @sqlHash
903
+ if @items.key?('ajax_action') && ! @items['ajax_action'].empty?
904
+ filterParameters['list_action'] = @items['ajax_action']
905
+ end
906
+
907
+ searchUrl = WidgetList::Utils::build_url(@items['pageId'], filterParameters, (!$_REQUEST.key?('BUTTON_VALUE')))
908
+
909
+ list_search = {}
910
+ #
911
+ # Search value
912
+ #
913
+ list_search['value'] = ''
914
+
915
+ if @items['searchSession']
916
+ if $_SESSION.key?('SEARCH_FILTER') && $_SESSION['SEARCH_FILTER'].key?(@items['name'])
917
+ list_search['value'] = $_SESSION['SEARCH_FILTER'][@items['name']]
918
+ end
919
+ end
920
+
921
+ #
922
+ # Search Input Field
923
+ #
924
+ list_search['list-search'] = true
925
+ list_search['width'] = '500'
926
+ list_search['input_class'] = 'info-input'
927
+ list_search['title'] = (@items['searchTitle'].empty?) ? @items['searchBtnName'] :@items['searchTitle']
928
+ list_search['id'] = 'list_search_id_' + @items['name']
929
+ list_search['name'] = 'list_search_name_' + @items['name']
930
+ list_search['class'] = 'inputOuter widget-search-outer ' + @items['name'].downcase + '-search'
931
+ list_search['search_ahead'] = {
932
+ 'url' => searchUrl,
933
+ 'skip_queue' => false,
934
+ 'target' => @items['name'],
935
+ 'search_form' => @items['list_search_form'],
936
+ 'onclick' => (! @items['searchOnclick'].empty? && ! @items['list_search_form'].empty?) ? @items['searchOnclick'] : '',
937
+ 'onkeyup' => (! @items['searchOnkeyup'].empty?) ? @items['searchOnkeyup'] : ''
938
+ }
939
+
940
+ @templateFill['<!--FILTER_HEADER-->'] = WidgetList::Widgets::widget_input(list_search)
941
+
942
+ end
943
+
944
+ #
945
+ # Grouping box
946
+ #
947
+ if ! @items['groupByItems'].empty?
948
+ list_group = {}
949
+ list_group['arrow_action'] = 'var stub;'
950
+ list_group['readonly'] = true
951
+ if @items['groupBySelected']
952
+ list_group['value'] = @items['groupBySelected']
953
+ else
954
+ list_group['value'] = @items['groupByItems'][0]
955
+ end
956
+
957
+ list_group['style'] = 'cursor:pointer;margin-left:5px;'
958
+ list_group['input_style'] = 'cursor:pointer;'
959
+ list_group['outer_onclick'] = 'ToggleAdvancedSearch(this);SelectBoxResetSelectedRow(\'' + @items['name'] + '\');'
960
+ list_group['list-search'] = false
961
+ list_group['width'] = '200' #hard code for now. needs to be dynamic based on max str length if this caller is made into a "WidgetFakeSelect"
962
+ list_group['id'] = 'list_group_id_' + @items['name']
963
+ list_group['name'] = 'list_group_name_' + @items['name']
964
+ list_group['class'] = 'inputOuter widget-search-outer ' + @items['name'].downcase + '-group'
965
+
966
+ className = ''
967
+ groupRows = []
968
+ if !@items['groupBySelected']
969
+ className = 'widget-search-results-row-selected'
970
+ end
971
+
972
+ @items['groupByItems'].each { |grouping|
973
+ if @items['groupBySelected'] && @items['groupBySelected'] === grouping
974
+ className = 'widget-search-results-row-selected'
975
+ end
976
+ groupRows << '<div class="widget-search-results-row ' + className + '" title="' + grouping + '" onmouseover="jQuery(\'.widget-search-results-row\').removeClass(\'widget-search-results-row-selected\')" onclick="SelectBoxSetValue(\'' + grouping + '\',\'' + @items['name'] + '\');' + @items['groupByClick'] + '">' + grouping + '</div>'
977
+ className = ''
978
+ }
979
+
980
+ list_group['search_ahead'] = {
981
+ 'skip_queue' => false,
982
+ 'search_form'=> '
983
+ <div id="advanced-search-container" style="height:100% !important;">
984
+ ' + groupRows.join("\n") + '
985
+ </div>',
986
+ 'onclick' => @items['searchOnclick']
987
+ }
988
+ if !@templateFill.key?('<!--FILTER_HEADER-->')
989
+ @templateFill['<!--FILTER_HEADER-->'] = ''
990
+ end
991
+ @templateFill['<!--FILTER_HEADER-->'] += '<div class="fake-select"><div class="label">' + @items['groupByLabel'] + ':</div> ' + WidgetList::Widgets::widget_input(list_group) + '</div>'
992
+ end
993
+ end
994
+ end
995
+ rescue Exception => e
996
+ out = '<tr><td colspan="50"><div id="noListResults">' + generate_error_output(e) + @items['noDataMessage'] + '</div></td></tr>'
997
+ if !@templateFill.key?('<!--DATA-->')
998
+ @templateFill['<!--DATA-->'] = out
999
+ else
1000
+ @templateFill['<!--DATA-->'] += out
1001
+ end
1002
+ end
1003
+
1004
+ return WidgetList::Utils::fill(@templateFill, @items['template'])
1005
+
1006
+ end
1007
+
1008
+ def build_pagination()
1009
+ pageRange = 3
1010
+ pageNext = 1
1011
+ pagePrev = 1
1012
+ showPrev = false
1013
+ showNext = true
1014
+ prevUrl = ''
1015
+ nextUrl = ''
1016
+ tags = ''
1017
+ urlTags = {}
1018
+ templates = {}
1019
+
1020
+ urlTags['SQL_HASH'] = @sqlHash
1021
+ urlTags['PAGE_ID'] = @items['pageId']
1022
+ urlTags['LIST_NAME'] = @items['name']
1023
+ urlTags['BUTTON_VALUE'] = @items['buttonVal']
1024
+ urlTags['LIST_FILTER_ALL'] = @items['LIST_FILTER_ALL']
1025
+
1026
+ templates['btn_previous'] = @items['template_pagination_previous_disabled']
1027
+ templates['btn_next'] = @items['template_pagination_next_active']
1028
+
1029
+ if $_REQUEST.key?('search_filter') && ! $_REQUEST['search_filter'].empty?
1030
+ urlTags['search_filter'] = $_REQUEST['search_filter']
1031
+ end
1032
+
1033
+ if @items['LIST_COL_SORT'].empty?
1034
+ urlTags['LIST_COL_SORT'] = @items['LIST_COL_SORT']
1035
+ urlTags['LIST_COL_SORT_ORDER'] = @items['LIST_COL_SORT_ORDER']
1036
+ urlTags['ROW_LIMIT'] = @items['ROW_LIMIT']
1037
+ end
1038
+
1039
+ if @items['links'].key?('paginate') && @items['links']['paginate'].class.name == 'Hash'
1040
+ @items['links']['paginate'].each { |tagName, tag|
1041
+ urlTags[tagName] = tag
1042
+ }
1043
+ end
1044
+
1045
+ if @items.key?('ajax_action') && ! @items['ajax_action'].empty?
1046
+ urlTags['list_action'] = @items['ajax_action']
1047
+ end
1048
+
1049
+ if (@sequence == @totalPages || ! (@totalPages > 0))
1050
+ showNext = false
1051
+ else
1052
+ urlTags['LIST_SEQUENCE'] = @sequence + 1
1053
+ nextUrl = WidgetList::Utils::build_url(@items['pageId'],urlTags,(!$_REQUEST.key?('BUTTON_VALUE')))
1054
+ end
1055
+
1056
+ if @sequence > 1
1057
+ pagePrev = @sequence - 1
1058
+ urlTags['LIST_SEQUENCE'] = pagePrev
1059
+ prevUrl = WidgetList::Utils::build_url(@items['pageId'],urlTags,(!$_REQUEST.key?('BUTTON_VALUE')))
1060
+ showPrev = true
1061
+ end
1062
+
1063
+ if !showNext
1064
+ templates['btn_next'] = @items['template_pagination_next_disabled']
1065
+ end
1066
+
1067
+ if showPrev
1068
+ templates['btn_previous'] = @items['template_pagination_previous_active']
1069
+ end
1070
+
1071
+ #Assemble navigation buttons
1072
+ #
1073
+ pieces = {
1074
+ '<!--NEXT_URL-->' => nextUrl,
1075
+ '<!--LIST_NAME-->' => @items['name'],
1076
+ '<!--HTTP_SERVER-->' => $_SERVER['rack.url_scheme'] + '://' + $_SERVER['HTTP_HOST'] + '/assets/',
1077
+ '<!--PREVIOUS_URL-->' => prevUrl,
1078
+ '<!--FUNCTION-->' => @items['ajax_function']
1079
+ }
1080
+
1081
+ templates['btn_next'] = WidgetList::Utils::fill(pieces,templates['btn_next'])
1082
+ templates['btn_previous'] = WidgetList::Utils::fill(pieces,templates['btn_previous'])
1083
+
1084
+ #
1085
+ # Sequence Range Drop Down
1086
+ #
1087
+ # Show x per page
1088
+ #
1089
+ urlTags['LIST_SEQUENCE'] = @sequence
1090
+ urlTags['ROW_LIMIT'] = 10
1091
+
1092
+ # Automate select box and rules
1093
+ #
1094
+ rowLimitSelect = [10,20,50,100,500,1000]
1095
+ rowLimitSelectData = {}
1096
+ rowLimitSelectConfigs = {}
1097
+
1098
+ #Set a default of 10
1099
+ #
1100
+ urlTags['ROW_LIMIT'] = 10
1101
+ options = ''
1102
+ rowLimitSelect.each_with_index { |jumpCount, key|
1103
+ if (@totalRows >= jumpCount || @totalRows > rowLimitSelect[key-1])
1104
+ urlTags['ROW_LIMIT'] = jumpCount
1105
+
1106
+ rowLimitUrl = WidgetList::Utils::build_url(@items['pageId'],urlTags,(!$_REQUEST.key?('BUTTON_VALUE')))
1107
+ selected = ''
1108
+ if (@items['rowLimit'] == jumpCount)
1109
+ selected = 'selected'
1110
+ end
1111
+ options += "<option value='#{rowLimitUrl}' #{selected}>#{jumpCount}</option> "
1112
+ end
1113
+ }
1114
+
1115
+ # WidgetSelect( todo)
1116
+ pageSelect = <<-EOD
1117
+ <select onchange="#{@items['ajax_function']}(this.value,'#{@items['name']}')" style="width:58px">
1118
+ #{options}
1119
+ </select>
1120
+ EOD
1121
+
1122
+ #Ensure the range does not exceed the actual number of pages
1123
+ #
1124
+ if @totalPages < pageRange
1125
+ pageRange = @totalPages
1126
+ end
1127
+
1128
+ ###
1129
+ # Create a range of x or less numbers.
1130
+ #
1131
+ # Take 2 off and add 2 or as much as possible either way
1132
+ ###
1133
+ startingPoint = @sequence
1134
+ vkill = pageRange
1135
+
1136
+ while vkill > 0 do
1137
+ vkill = vkill - 1
1138
+ if startingPoint <= 1
1139
+ break
1140
+ else
1141
+ startingPoint = startingPoint-1
1142
+ end
1143
+ end
1144
+
1145
+ endPoint = @sequence
1146
+ vkill = pageRange
1147
+
1148
+ while vkill > 0 do
1149
+ vkill = vkill - 1
1150
+ if endPoint <= 1
1151
+ endPoint = endPoint+1
1152
+ else
1153
+ break
1154
+ end
1155
+ end
1156
+
1157
+ jumpSection = []
1158
+
1159
+ #Builds jump section previous 4 5 6 7 next
1160
+ #
1161
+ for page in startingPoint..endPoint
1162
+ urlTags['LIST_SEQUENCE'] = page
1163
+ urlTags['SQL_HASH'] = @sqlHash
1164
+ jumpTemplate = ''
1165
+ jumpUrl = ''
1166
+ jumpUrl = WidgetList::Utils::build_url(@items['pageId'], urlTags, (!$_REQUEST.key?('BUTTON_VALUE')))
1167
+
1168
+ if page == @sequence
1169
+ jumpTemplate = @items['template_pagination_jump_active']
1170
+ else
1171
+ jumpTemplate = @items['template_pagination_jump_unactive']
1172
+ end
1173
+
1174
+ jumpSection << WidgetList::Utils::fill({'<!--SEQUENCE-->'=>page,'<!--JUMP_URL-->'=>jumpUrl,'<!--LIST_NAME-->'=>@items['name'],'<!--FUNCTION-->'=>@items['ajax_function']}, jumpTemplate)
1175
+ end
1176
+
1177
+ pieces = {
1178
+ '<!--PREVIOUS_BUTTON-->' => templates['btn_previous'],
1179
+ '<!--SEQUENCE-->' => @sequence,
1180
+ '<!--NEXT_BUTTON-->' => templates['btn_next'],
1181
+ '<!--TOTAL_PAGES-->' => @totalPages,
1182
+ '<!--TOTAL_ROWS-->' => @totalRows,
1183
+ '<!--PAGE_SEQUENCE_JUMP_LIST-->' => pageSelect,
1184
+ '<!--JUMP-->' => jumpSection.join(''),
1185
+ '<!--LIST_NAME-->' => @items['name'],
1186
+ }
1187
+
1188
+ paginationOutput = WidgetList::Utils::fill(pieces,@items['template_pagination_wrapper'])
1189
+
1190
+ if (@items['showPagination'])
1191
+ return paginationOutput
1192
+ else
1193
+ return ''
1194
+ end
1195
+
1196
+ end
1197
+
1198
+ def build_headers()
1199
+ headers = []
1200
+ @items['fields'].each { |field, fieldTitle|
1201
+ colWidthStyle = '';
1202
+ colClass = '';
1203
+ popupTitle = '';
1204
+ templateIdx = 'templateNoSortColumn'
1205
+
1206
+ #Column class
1207
+ #
1208
+ if ! @items['headerClass'].empty?
1209
+ if @items['headerClass'].key?(field.downcase)
1210
+ colClass = @items['headerClass'][field.downcase]
1211
+ end
1212
+ end
1213
+
1214
+ #Column width
1215
+ #
1216
+ if ! @items['columnWidth'].empty?
1217
+ if @items['columnWidth'].key?(field.downcase)
1218
+ colWidthStyle = "width:" + @items['columnWidth'][field.downcase] + ";"
1219
+ end
1220
+ end
1221
+
1222
+ $_SESSION.deep_merge!({'LIST_SEQUENCE' => { @sqlHash => @sequence} })
1223
+
1224
+ #Hover Title
1225
+ #
1226
+ if @items['columnPopupTitle'].key?(field.downcase)
1227
+ popupTitle = @items['columnPopupTitle'][field.downcase]
1228
+ end
1229
+
1230
+
1231
+ #
1232
+ # Column is an input
1233
+ #
1234
+ if @items['inputs'].key?(fieldTitle) && @items['inputs'][fieldTitle].class.name == 'Hash'
1235
+ #
1236
+ # Default checkbox hover to "Select All"
1237
+ #
1238
+ # Do specific input type functions
1239
+ #
1240
+ case @items['inputs'][fieldTitle]['type']
1241
+ when 'checkbox'
1242
+
1243
+ if popupTitle.empty? && @items['inputs'][fieldTitle]['items']['check_all']
1244
+ popupTitle = 'Select All'
1245
+ end
1246
+
1247
+ #
1248
+ # No sort on this column
1249
+ #
1250
+ if ! @items['columnNoSort'].key?(fieldTitle)
1251
+ @items['columnNoSort'][field] = field
1252
+ end
1253
+
1254
+ if colClass.empty?
1255
+ @items['headerClass'] = { fieldTitle => 'widgetlist-checkbox-header'}
1256
+ colClass = @items['headerClass'][fieldTitle]
1257
+ end
1258
+ end
1259
+
1260
+ #
1261
+ # Build the input
1262
+ #
1263
+ fieldTitle = build_column_input(fieldTitle)
1264
+
1265
+ end
1266
+
1267
+ if (@items['useSort'] && (@items['columnSort'].include?(field) || (@items['columnSort'].key?(field)) && !@items['columnNoSort'].include?(field)) || (@items['columnSort'].empty? && !@items['columnNoSort'].include?(field)))
1268
+
1269
+ templateIdx = 'templateSortColumn'
1270
+ colSort = {}
1271
+
1272
+ #Assign the column to be sorted
1273
+ #
1274
+ if !@items['columnSort'].empty? && @items['columnSort'].key?(field)
1275
+ colSort['LIST_COL_SORT'] = @items['columnSort'][field]
1276
+ elsif (!@items['columnSort'].empty? && @items['columnSort'].include?(field)) || @items['columnSort'].empty?
1277
+ colSort['LIST_COL_SORT'] = field
1278
+ end
1279
+
1280
+ colSort['PAGE_ID'] = @items['pageId']
1281
+ colSort['LIST_NAME'] = @items['name']
1282
+ colSort['BUTTON_VALUE'] = @items['buttonVal']
1283
+ colSort['LIST_COL_SORT_ORDER'] = @listSortNext
1284
+ colSort['LIST_FILTER_ALL'] = @items['LIST_FILTER_ALL']
1285
+ colSort['ROW_LIMIT'] = @items['ROW_LIMIT']
1286
+ colSort['LIST_SEQUENCE'] = @sequence
1287
+
1288
+ icon = ""
1289
+
1290
+ if (
1291
+ ( (@items.key?('LIST_COL_SORT') && !@items['LIST_COL_SORT'].empty?) && @items['LIST_COL_SORT'] == colSort['LIST_COL_SORT']) ||
1292
+ ( $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].key?(@sqlHash) && $_SESSION['LIST_COL_SORT'][@sqlHash].key?(field))
1293
+ )
1294
+ changedSession = false
1295
+ if @items.key?('LIST_COL_SORT') && !@items['LIST_COL_SORT'].empty?
1296
+ changedSession = ( $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].key?(@sqlHash) && ! $_SESSION['LIST_COL_SORT'][@sqlHash].key?(@items['LIST_COL_SORT']) )
1297
+ if $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].key?(@sqlHash)
1298
+ $_SESSION['LIST_COL_SORT'].delete(@sqlHash)
1299
+ end
1300
+ $_SESSION.deep_merge!({'LIST_COL_SORT' => { @sqlHash => {@items['LIST_COL_SORT']=> @items['LIST_COL_SORT_ORDER'] } } })
1301
+ end
1302
+
1303
+ if !changedSession && @items.key?('LIST_COL_SORT') && ! @items['LIST_COL_SORT'].empty?
1304
+ if @items['LIST_COL_SORT_ORDER'] == 'DESC'
1305
+ icon = "&uarr;"
1306
+ else
1307
+ icon = "&darr;"
1308
+ end
1309
+ elsif !changedSession && $_SESSION['LIST_COL_SORT'].class.name == 'Hash' && $_SESSION['LIST_COL_SORT'].key?(@sqlHash)
1310
+ #load sort from session
1311
+ $_SESSION['LIST_COL_SORT'][@sqlHash].each_with_index { |order,void|
1312
+ if order[1] == 'DESC'
1313
+ colSort['LIST_COL_SORT_ORDER'] = "ASC"
1314
+ icon = "&uarr;"
1315
+ else
1316
+ colSort['LIST_COL_SORT_ORDER'] = "DESC"
1317
+ icon = "&darr;"
1318
+ end
1319
+ }
1320
+ end
1321
+ end
1322
+
1323
+ #Carry over any search criteria on a sort to SORT URL
1324
+ #
1325
+ if $_REQUEST.key?('search_filter') && ! $_REQUEST['search_filter'].empty?
1326
+ if $_REQUEST['search_filter'].empty?
1327
+ colSort['search_filter'] = $_REQUEST['search_filter']
1328
+ end
1329
+ end
1330
+
1331
+ if @items.key?('ajax_action') && ! @items['ajax_action'].empty?
1332
+ colSort['list_action'] = @items['ajax_action']
1333
+ end
1334
+ colSort['SQL_HASH'] = @sqlHash
1335
+
1336
+ pieces = { '<!--COLSORTURL-->' => WidgetList::Utils::build_url(@items['pageId'],colSort,(!$_REQUEST.key?('BUTTON_VALUE'))),
1337
+ '<!--NAME-->' => @items['name'],
1338
+ '<!--COLSORTICON->' => icon,
1339
+ '<!--COL_HEADER_ID-->' => strip_tags(field).gsub(/\s/,'_'),
1340
+ '<!--INLINE_STYLE-->' => colWidthStyle,
1341
+ '<!--TITLE_POPUP-->' => popupTitle,
1342
+ '<!--COL_HEADER_CLASS-->' => colClass,
1343
+ '<!--TITLE-->' => fieldTitle,
1344
+ '<!--FUNCTION-->' => @items['ajax_function']
1345
+ }
1346
+ headers << WidgetList::Utils::fill(pieces, @items[templateIdx])
1347
+ else
1348
+ pieces = { '<!--TITLE-->' => fieldTitle,
1349
+ '<!--INLINE_STYLE-->' => colWidthStyle,
1350
+ '<!--TITLE_POPUP-->' => popupTitle,
1351
+ '<!--COL_HEADER_CLASS-->' => colClass,
1352
+ '<!--COL_HEADER_ID-->' => strip_tags(field).gsub(/\s/,'_')
1353
+ }
1354
+
1355
+ headers << WidgetList::Utils::fill(pieces, @items[templateIdx])
1356
+ end
1357
+ }
1358
+
1359
+ @templateFill['<!--COLSPAN_FULL-->'] = headers.count()
1360
+
1361
+ if @items['mode'] != 'passive'
1362
+ pieces = {'<!--LIST_SEQUENCE-->' => @sequence,
1363
+ '<!--TOTAL_PAGES-->' => @totalPages}
1364
+
1365
+ @templateFill['<!--PAGE_SEQUENCE_DISPLAY-->'] = WidgetList::Utils::fill(pieces, @items['templateSequence'])
1366
+ end
1367
+
1368
+ @templateFill['<!--PAGINATION_LIST-->'] = build_pagination()
1369
+ @templateFill['<!--HEADERS-->'] = headers.join('')
1370
+
1371
+ if ! @items['listDescription'].empty?
1372
+ fillDesc = {}
1373
+ fillDesc['<!--COLSPAN-->'] = headers.count()
1374
+ fillDesc['<!--LIST_DESCRIPTION-->'] = @items['listDescription']
1375
+ fillDesc['<!--LIST_NAME-->'] = @items['name']
1376
+ @templateFill['<!--LIST_TITLE-->'] = WidgetList::Utils::fill(fillDesc,@items['list_description'])
1377
+ else
1378
+ @templateFill['<!--LIST_TITLE-->'] = ''
1379
+ end
1380
+
1381
+ end
1382
+
1383
+ # @param [String] column (the name)
1384
+ # @param [Fixnum] row (the id or pointer in the loop to fetch the data)
1385
+ def build_column_input(column, row='')
1386
+ content = ''
1387
+
1388
+ inputManager = @items['inputs'][column]
1389
+ case inputManager['type']
1390
+ when "checkbox"
1391
+
1392
+
1393
+ input = {}
1394
+ input['name'] = 'widget_check_name'
1395
+ input['id'] = 'widget_check_id'
1396
+ input['check_all'] = false
1397
+ input['value'] = ''
1398
+ input['checked'] = ''
1399
+ input['onclick'] = ''
1400
+ input['input_class'] = 'widgetlist-checkbox-input'
1401
+
1402
+ input['class_handle'] = ''
1403
+
1404
+ input = WidgetList::Widgets::populate_items(inputManager['items'],input)
1405
+
1406
+ onClick = []
1407
+ checkAllId = ''
1408
+
1409
+ #
1410
+ # Get a value. Assumes it is a column initially.
1411
+ #
1412
+ # @note headers are ignored and would fail as row would be null
1413
+ #
1414
+ if @results.key?(input['value'].upcase) && !@results[input['value'].upcase][row].to_s.empty?
1415
+ input['value'] = @results[ input['value'].upcase ][row]
1416
+ end
1417
+
1418
+ #
1419
+ # Append class handle
1420
+ #
1421
+ input['input_class'] = "#{input['input_class']} #{input['class_handle']}"
1422
+
1423
+ if input['check_all']
1424
+ checkAllId = input['id']
1425
+ if $_SESSION.key?('list_checks') && $_SESSION['list_checks'].key?('check_all_' + @sqlHash.to_s + @items['name'].to_s + @sequence.to_s)
1426
+ input['checked'] = true
1427
+ end
1428
+
1429
+ #
1430
+ # Set header class
1431
+ #
1432
+ if @items['headerClass'].class.name == 'Array' && @items['headerClass'].key?('checkbox')
1433
+ if $_SESSION['list_checks'].key?('check_all_' + @sqlHash.to_s + @items['name'].to_s + @sequence.to_s)
1434
+ input['checked'] = true
1435
+ end
1436
+ end
1437
+ else
1438
+ input['input_class'] = "#{input['input_class']} #{input['class_handle']} #{input['class_handle']}_list"
1439
+ end
1440
+
1441
+ #
1442
+ # Setup onclick action
1443
+ #
1444
+ if input['onclick'].empty?
1445
+ listJumpUrl = {}
1446
+ listJumpUrl['BUTTON_VALUE'] = @items['buttonVal']
1447
+ listJumpUrl['LIST_COL_SORT'] = @items['LIST_COL_SORT']
1448
+ listJumpUrl['LIST_COL_SORT_ORDER'] = @items['LIST_COL_SORT_ORDER']
1449
+ listJumpUrl['LIST_FILTER_ALL'] = @items['LIST_FILTER_ALL']
1450
+ listJumpUrl['ROW_LIMIT'] = @items['ROW_LIMIT']
1451
+ listJumpUrl['LIST_SEQUENCE'] = @sequence
1452
+ listJumpUrl['LIST_NAME'] = @items['name']
1453
+ listJumpUrl['SQL_HASH'] = @sqlHash
1454
+ listJumpUrl['list_action'] = 'ajax_widgetlist_checks'
1455
+
1456
+ onClick << "AjaxMaintainChecks(this, '#{input['class_handle']}', '#{@items['name']}', '" + WidgetList::Utils::build_url(@items['pageId'],listJumpUrl,(!$_REQUEST.key?('BUTTON_VALUE'))) + "', '#{checkAllId}');"
1457
+ end
1458
+
1459
+ input['onclick'] = onClick.join(' ')
1460
+
1461
+ #
1462
+ # Checkbox is checked or not per query value
1463
+ #
1464
+ if ! @items['checked_flag'].empty?
1465
+ if @items['checked_flag'].key?(column)
1466
+ input['checked'] = !!@results[ @items['checked_flag'][column].upcase ][row]
1467
+ end
1468
+ end
1469
+
1470
+ #
1471
+ # Checkbox is checked or not per session (overwrites query)
1472
+ #
1473
+ if $_SESSION.key?('list_checks') && $_SESSION['list_checks'].key?(@items['name'] + @sqlHash + input['value'].to_s)
1474
+ input['checked'] = true
1475
+ end
1476
+
1477
+ content = WidgetList::Widgets::widget_check(input)
1478
+
1479
+ #todo never implemented
1480
+
1481
+ when "text"
1482
+ a=1
1483
+ #content = WidgetInput()
1484
+
1485
+ when "select"
1486
+ a=1
1487
+ #content = WidgetSelect()
1488
+
1489
+ end
1490
+
1491
+ return content
1492
+ end
1493
+
1494
+ def build_column_button(column,j)
1495
+ buttons = @items['buttons'][column]
1496
+ columnValue = @results[column.upcase][j]
1497
+ btnOut = []
1498
+ strCnt = 0
1499
+ nameId = ''
1500
+
1501
+ buttons.each { |buttonId,buttonAttribs|
1502
+ #url = array('PAGE_ID')
1503
+ function = @items['linkFunction']
1504
+ parameters = ''
1505
+ renderButton = true
1506
+
1507
+ if buttonAttribs.key?('tags')
1508
+ buttonAttribs['tags'].each { | tagName , tag |
1509
+ #only uppercase will be replaced
1510
+ #
1511
+
1512
+ if @results.key?(tag.upcase) && @results[tag.upcase][j]
1513
+
1514
+ buttonAttribs.deep_merge!({'args' =>
1515
+ {
1516
+ tagName => @results[tag.upcase][j]
1517
+ }
1518
+ })
1519
+ else
1520
+ buttonAttribs.deep_merge!({'args' =>
1521
+ {
1522
+ tagName => tag
1523
+ }
1524
+ })
1525
+ end
1526
+ }
1527
+ end
1528
+ nameId = buttonId.to_s + '_' + j.to_s
1529
+
1530
+ buttonAttribs['name'] = nameId
1531
+ buttonAttribs['id'] = nameId
1532
+
1533
+ #if buttonAttribs.key?('condition')
1534
+ #never show button if you pass a condition unless explicitly matching the value of the features
1535
+ #
1536
+ #renderButton = false
1537
+ #allConditions = columnValue.split(':')
1538
+ #if (in_array(ltrim($buttonAttribs['condition'], ':'), $allConditions))
1539
+ # renderButton = true
1540
+ #end
1541
+ #end
1542
+
1543
+ if (renderButton)
1544
+ strCnt += (buttonAttribs['text'].length * 15)
1545
+ btnOut << WidgetList::Widgets::widget_button(buttonAttribs['text'], buttonAttribs, true)
1546
+ end
1547
+ }
1548
+
1549
+ #BS width algorithm. HACK/TWEAK/OMG Get it working.
1550
+ #
1551
+ colWidth = ((strCnt + (btnOut.count * 35)) / 2) + 10
1552
+
1553
+ return '<div style="border:0px solid black;text-align:center;white-space:nowrap;margin:auto;width:' + colWidth.to_s + 'px"><div style="margin:auto;display:inline-block">' + btnOut.join('') + '</div></div>'
1554
+ end
1555
+
1556
+ # @param [String] column
1557
+ def build_column_link(column,j)
1558
+
1559
+ links = @items['links'][column]
1560
+ url = {'PAGE_ID' => @items['pageId']}
1561
+ function = @items['linkFunction']
1562
+ parameters = ''
1563
+
1564
+ if links.key?('PAGE_ID') && ! links['PAGE_ID'].empty?
1565
+ url['PAGE_ID'] = links['PAGE_ID']
1566
+ end
1567
+
1568
+ if links.key?('ACTION') && ! links['ACTION'].empty?
1569
+ url['list_action'] = links['ACTION']
1570
+ end
1571
+
1572
+ if links.key?('BUTTON_VALUE') && ! links['BUTTON_VALUE'].empty?
1573
+ url['BUTTON_VALUE'] = links['BUTTON_VALUE']
1574
+ end
1575
+
1576
+ #todo unit test this and all of column links
1577
+ if links.key?('tags')
1578
+ links['tags'].each { | tagName, tag |
1579
+ if @results[tag][j]
1580
+ url[tagName] = @results[tag][j]
1581
+ else
1582
+ url[tagName] = tag
1583
+ end
1584
+ }
1585
+ end
1586
+
1587
+ if links.key?('onclick') && links['onclick'].class.name == 'Hash'
1588
+ if links['onclick'].key?('function') && !links['onclick']['function'].empty?
1589
+ function = links['onclick']['function']
1590
+ end
1591
+
1592
+ if links['onclick'].key?('tags') && !links['onclick']['tags'].empty?
1593
+ links['onclick']['tags'].each { | tagName , tag|
1594
+ if @results.key?(tag.upcase)
1595
+ parameters = ", '" + @results[tag.upcase][j] + "'"
1596
+ end
1597
+ }
1598
+ end
1599
+ end
1600
+
1601
+ if @items.key?('ajax_action') && !@items['ajax_action'].empty?
1602
+ url['list_action'] = @items['ajax_action']
1603
+ end
1604
+
1605
+ url['SQL_HASH'] = @sqlHash
1606
+ linkUrl = WidgetList::Utils::build_url(@items['pageId'],(!$_REQUEST.key?('BUTTON_VALUE')))
1607
+
1608
+ "#{function}('#{linkUrl}'#{parameters})"
1609
+ end
1610
+
1611
+ def build_rows()
1612
+ sql = build_statement()
1613
+ if @totalResultCount > 0
1614
+ if @items['data'].empty?
1615
+ #Run the actual statement
1616
+ #
1617
+ @totalRowCount = WidgetList::List.get_database._select(sql, @items['bindVars'], @items['bindVarsLegacy'])
1618
+ end
1619
+
1620
+ if @totalRowCount > 0
1621
+ if @items['data'].empty?
1622
+ @results = WidgetList::List.get_database.final_results
1623
+ else
1624
+ @results = @items['data']
1625
+ end
1626
+
1627
+ #Build each row
1628
+ #
1629
+ max = @totalRowCount-1
1630
+ rows = []
1631
+ j = 0
1632
+ for j in j..max
1633
+ columns = []
1634
+ customRowColor = ''
1635
+ customRowStyle = ''
1636
+
1637
+ #
1638
+ # For each column (field) in this row
1639
+ #
1640
+
1641
+ @items['fields'].each { |column , fieldTitle|
1642
+ colPieces = {}
1643
+ colClasses = []
1644
+ theStyle = ''
1645
+ colData = ''
1646
+ colClass = ''
1647
+ onClick = ''
1648
+ colWidthStyle = ''
1649
+ content = ''
1650
+ contentTitle = ''
1651
+
1652
+
1653
+
1654
+ #todo unit test build_column_link
1655
+
1656
+ #
1657
+ # Column is a Link
1658
+ #
1659
+ if @items['links'].key?(column) && @items['links'][column].class.name == 'Hash'
1660
+ onClick = build_column_link(column,j)
1661
+
1662
+ #
1663
+ # Column is a Button
1664
+ #
1665
+ elsif @items['buttons'].key?(column) && @items['buttons'][column].class.name == 'Hash'
1666
+ content = build_column_button(column, j)
1667
+
1668
+
1669
+ #
1670
+ # Column is an input
1671
+ #
1672
+ elsif @items['inputs'].key?(column) && @items['inputs'][column].class.name == 'Hash'
1673
+ colClasses << @items['checked_class']
1674
+ content = build_column_input(column, j)
1675
+
1676
+
1677
+ #
1678
+ # Column is text
1679
+ #
1680
+ else
1681
+ cleanData = strip_tags(@results[column.upcase][j].to_s)
1682
+
1683
+ if cleanData.length > @items['strlength']
1684
+ =begin
1685
+ $contentTitle = $cleanData;
1686
+
1687
+ $possibleMatches = array("/(.*)(\(<a.*?>.*?<\/a>\)\s)(.*)/i" => array(3), #<a>(id)</a> Text
1688
+ "/(.*)(<a.*?>)(.*)(<\/a>)(.*)/i" => array(3) #<a>Text</a> other text
1689
+ );
1690
+
1691
+ foreach($possibleMatches as $regex => $toFix)
1692
+ {
1693
+ $matched = preg_match_all($regex, @results[strtoupper($column)][$j], $matches, PREG_PATTERN_ORDER);
1694
+
1695
+ if(! empty($matched))
1696
+ {
1697
+ $pieces = {};
1698
+
1699
+ unset($matches[0]);
1700
+
1701
+ foreach($matches as $key => $theText)
1702
+ {
1703
+ $fixedText = '';
1704
+
1705
+ if(in_array($key, $toFix))
1706
+ {
1707
+ $fixedText = substr($theText[0], 0, @items['strlength']) . '...';
1708
+ }
1709
+ else
1710
+ {
1711
+ $fixedText = $theText[0];
1712
+ }
1713
+
1714
+ $pieces[] = $fixedText;
1715
+ }
1716
+
1717
+ $content = implode('', $pieces);
1718
+
1719
+ break;
1720
+ }
1721
+ }
1722
+
1723
+ if(empty($matched))
1724
+ {
1725
+ if ((strpos(@results[strtoupper($column)][$j],'&#') !== false && strpos(@results[strtoupper($column)][$j],';') !== false))
1726
+ {
1727
+ $content = @results[strtoupper($column)][$j];
1728
+ }
1729
+ else
1730
+ {
1731
+ $content = substr(@results[strtoupper($column)][$j], 0, @items['strlength']) . '...';
1732
+ }
1733
+ }
1734
+ =end
1735
+ content = @results[column.upcase][j].to_s[ 0, @items['strlength'] ] + '...'
1736
+
1737
+ else
1738
+ content = @results[column.upcase][j].to_s
1739
+ end
1740
+
1741
+ #Strip HTML
1742
+ #
1743
+ if !@items['allowHTML']
1744
+ content = strip_tags(content)
1745
+ end
1746
+ content = WidgetList::List.get_database._bind(content, @items['bindVarsLegacy'])
1747
+
1748
+ # Column color
1749
+ #
1750
+ if ! @items['columnStyle'].empty?
1751
+ if @items['columnStyle'].key?(column.downcase)
1752
+ colHeader = @items['columnStyle'][column.downcase]
1753
+
1754
+ if @results.key?(colHeader.upcase)
1755
+ theStyle = @results[colHeader.upcase][j]
1756
+ else
1757
+ theStyle = colHeader
1758
+ end
1759
+
1760
+ end
1761
+ end
1762
+
1763
+ # Column width
1764
+ #
1765
+ if ! @items['columnWidth'].empty?
1766
+ if @items['columnWidth'].key?(column.downcase)
1767
+ colWidthStyle = "width:" + @items['columnWidth'][column.downcase] + ";"
1768
+ end
1769
+ end
1770
+
1771
+ # Column Class
1772
+ #
1773
+ if !@items['columnClass'].empty?
1774
+ if @items['columnClass'].key?(column.downcase)
1775
+ colClasses << @items['columnClass'][column.downcase]
1776
+ end
1777
+ end
1778
+
1779
+ end
1780
+
1781
+
1782
+ #
1783
+ # Setup any column classes
1784
+ #
1785
+ colClasses << @items['collClass']
1786
+ colClass = colClasses.join(' ')
1787
+
1788
+ #
1789
+ # Row Color
1790
+ #
1791
+ if !@items['rowColorByStatus'].empty? && @items['rowColorByStatus'].key?(column) && !@items['rowColorByStatus'][column].empty?
1792
+ @items['rowColorByStatus'][column].each { |status,color|
1793
+ if status === content
1794
+ customRowColor = color
1795
+ end
1796
+ }
1797
+ end
1798
+
1799
+ #
1800
+ # Row Style
1801
+ #
1802
+ if !@items['rowStylesByStatus'].empty? && @items['rowStylesByStatus'].key?(column) && !@items['rowStylesByStatus'][column].empty?
1803
+ @items['rowStylesByStatus'][column].each { |status,inlineStyle|
1804
+ if status === content
1805
+ customRowStyle = color
1806
+ end
1807
+ }
1808
+ end
1809
+
1810
+ #
1811
+ # Set up Column Pieces
1812
+ #
1813
+ colPieces['<!--CLASS-->'] = colClass
1814
+ colPieces['<!--ALIGN-->'] = @items['collAlign']
1815
+ colPieces['<!--STYLE-->'] = theStyle + colWidthStyle
1816
+ colPieces['<!--ONCLICK-->'] = onClick
1817
+ colPieces['<!--TITLE-->'] = contentTitle #todo htmlentities needed ?
1818
+ colPieces['<!--CONTENT-->'] = content
1819
+ #
1820
+ # Assemble the Column
1821
+ #
1822
+ columns << WidgetList::Utils::fill(colPieces, @items['col'])
1823
+
1824
+ }
1825
+
1826
+ #Draw the row
1827
+ #
1828
+
1829
+ pieces = {'<!--CONTENT-->' => columns.join('') }
1830
+ if @items['rowColorByStatus'].empty? && @items['rowStylesByStatus'].empty?
1831
+ #Set the row color
1832
+ #
1833
+ rowColor = @items['rowColor']
1834
+
1835
+ if @items['offsetRows']
1836
+ if( j % 2 ==0)
1837
+ rowColor = @items['rowOffsets'][1]
1838
+ else
1839
+ rowColor = @items['rowOffsets'][0]
1840
+ end
1841
+ end
1842
+
1843
+ #Draw default color
1844
+ #
1845
+ pieces['<!--BGCOLOR-->'] = rowColor
1846
+ pieces['<!--ROWSTYLE-->'] = ''
1847
+ pieces['<!--ROWCLASS-->'] = @items['rowClass']
1848
+ else
1849
+ pieces['<!--BGCOLOR-->'] = !customRowColor.empty? ? customRowColor : @items['rowColor']
1850
+ pieces['<!--ROWSTYLE-->'] = customRowStyle.empty? ? customRowStyle : ''
1851
+ pieces['<!--ROWCLASS-->'] = @items['rowClass']
1852
+ end
1853
+ rows << WidgetList::Utils::fill(pieces, @items['row'])
1854
+
1855
+ end
1856
+
1857
+ @templateFill['<!--DATA-->'] = rows.join('')
1858
+
1859
+ else
1860
+ @templateFill['<!--DATA-->'] = '<tr><td colspan="50"><div id="noListResults">' + generate_error_output() + @items['noDataMessage'] + '</div></td></tr>'
1861
+ end
1862
+
1863
+ else
1864
+ @templateFill['<!--DATA-->'] = '<tr><td colspan="50"><div id="noListResults">' + generate_error_output() + @items['noDataMessage'] + '</div></td></tr>'
1865
+ end
1866
+
1867
+ end
1868
+
1869
+ def generate_error_output(ex='')
1870
+ sqlDebug = ""
1871
+ if Rails.env == 'development'
1872
+ sqlDebug += "<br/><br/><textarea style='width:100%;height:400px;'>" + WidgetList::List.get_database.last_sql.to_s + "</textarea>"
1873
+ end
1874
+
1875
+ if Rails.env == 'development' && WidgetList::List.get_database.errors
1876
+ sqlDebug += "<br/><br/><strong style='color:red'>(" + WidgetList::List.get_database.last_error.to_s + ")</strong>"
1877
+ end
1878
+
1879
+ if Rails.env == 'development' && ex != ''
1880
+ sqlDebug += "<br/><br/><strong style='color:red'>(" + ex.to_s + ") <pre>" + $!.backtrace.join("\n\n") + "</pre></strong>"
1881
+ end
1882
+
1883
+ sqlDebug
1884
+ end
1885
+
1886
+ def build_statement()
1887
+ statement = ''
1888
+ pieces = { '<!--FIELDS-->' => '',
1889
+ '<!--SOURCE-->' => '',
1890
+ '<!--WHERE-->' => '',
1891
+ '<!--GROUPBY-->' => '',
1892
+ '<!--ORDERBY-->' => '',
1893
+ '<!--LIMIT-->' => ''}
1894
+
1895
+ if !@items['sql'].empty? || !@items['force_query_sql'].empty?
1896
+ if !@items['fieldNames'].empty?
1897
+ @items['fieldNames'].each { |column|
1898
+ tick = '`'
1899
+ if(isset(@items['function'][column]))
1900
+ tick = ''
1901
+ column = @items['function'][column]
1902
+ end
1903
+ @fieldList << "#{tick}#{column}#{tick}"
1904
+ }
1905
+ fields = @fieldList.join(',')
1906
+
1907
+
1908
+ else
1909
+ fields = "*";
1910
+ end
1911
+
1912
+
1913
+ sqlPieces = {};
1914
+ sqlPieces['<!--FIELDS-->'] = fields;
1915
+ sqlPieces['<!--SQL-->'] = @items['sql'];
1916
+
1917
+ if !@items['force_query_sql'].empty?
1918
+ statement = @items['force_query_sql']
1919
+ else
1920
+ statement = @items['statement']['select']['sql']
1921
+ end
1922
+
1923
+ statement = WidgetList::Utils::fill(sqlPieces, @items['statement']['count']['table'])
1924
+
1925
+ elsif !@items['view'].empty?
1926
+ #Build out a list of columns to select from
1927
+ #
1928
+ @items['fields'].each { |column, fieldTitle|
1929
+ if @items['function'].key?(column) && !@items['function'][column].empty?
1930
+ column = @items['function'][column]
1931
+ end
1932
+
1933
+ @fieldList << column
1934
+ }
1935
+
1936
+ #Add any columns without corresponding header titles
1937
+ #
1938
+ @items['columns'].each { |column|
1939
+ @fieldList << column
1940
+ }
1941
+
1942
+ viewPieces = {}
1943
+ viewPieces['<!--FIELDS-->'] = @fieldList.join(',')
1944
+ viewPieces['<!--SOURCE-->'] = @items['view']
1945
+
1946
+ statement = WidgetList::Utils::fill(viewPieces, @items['statement']['select']['view'])
1947
+ end
1948
+
1949
+ @sqlHash = Digest::SHA2.hexdigest( WidgetList::Utils::fill(pieces, statement) )
1950
+
1951
+ if @items['searchClear'] || @items['searchClearAll']
1952
+ clear_sql_session(@items.key?('searchClearAll'))
1953
+ end
1954
+
1955
+ if !$_REQUEST.key?('BUTTON_VALUE') && $_SESSION.key?('LIST_SEQUENCE') && $_SESSION['LIST_SEQUENCE'].key?(@sqlHash) && $_SESSION['LIST_SEQUENCE'][@sqlHash] > 0
1956
+ @sequence = $_SESSION['LIST_SEQUENCE'][@sqlHash]
1957
+ generate_limits
1958
+ end
1959
+
1960
+ if !@filter.empty?
1961
+ where = ' WHERE '
1962
+ pieces['<!--WHERE-->'] = where + @filter
1963
+ end
1964
+
1965
+ if !@items['groupBy'].empty?
1966
+ pieces['<!--GROUPBY-->'] += ' GROUP BY ' + @items['groupBy']
1967
+ end
1968
+
1969
+ if !@items['LIST_COL_SORT'].empty? || $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].class.name == 'Hash' && $_SESSION['LIST_COL_SORT'].key?(@sqlHash)
1970
+ if ! @items['LIST_COL_SORT'].empty?
1971
+ pieces['<!--ORDERBY-->'] += ' ORDER BY `' + @items['LIST_COL_SORT'] + "` " + @items['LIST_COL_SORT_ORDER']
1972
+ else
1973
+ $_SESSION['LIST_COL_SORT'][@sqlHash].each_with_index { |order,void|
1974
+ pieces['<!--ORDERBY-->'] += ' ORDER BY `' + order[0] + "` " + order[1]
1975
+ } if $_SESSION.key?('LIST_COL_SORT') && $_SESSION['LIST_COL_SORT'].class.name == 'Hash' && $_SESSION['LIST_COL_SORT'].key?(@sqlHash)
1976
+ end
1977
+
1978
+ # Add base order by
1979
+ if ! @items['orderBy'].empty?
1980
+ pieces['<!--ORDERBY-->'] += ',' + @items['orderBy']
1981
+ end
1982
+
1983
+ elsif !@items['orderBy'].empty?
1984
+ pieces['<!--ORDERBY-->'] += ' ORDER BY ' + @items['orderBy']
1985
+ end
1986
+
1987
+ pieces['<!--LIMIT-->'] = ' LIMIT :LOW, :HIGH'
1988
+
1989
+ statement = WidgetList::Utils::fill(pieces, statement)
1990
+
1991
+ if @items['rowLimit'] >= @totalRows
1992
+ @items['bindVarsLegacy']['LOW'] = 0
1993
+ @sequence = 1
1994
+ end
1995
+
1996
+ statement
1997
+ end
1998
+
1999
+ def auto_column_name(name='')
2000
+ name.gsub(/\_/,' ').gsub(/\-/,' ').capitalize
2001
+ end
2002
+
2003
+ def get_total_records()
2004
+
2005
+ filter = ''
2006
+ fields = {}
2007
+ sql = ''
2008
+ hashed = false
2009
+
2010
+ if !@items['force_count_sql'].empty?
2011
+ sql = @items['force_count_sql']
2012
+ elsif !@items['table'].empty?
2013
+ sql = WidgetList::Utils::fill({'<!--TABLE-->' => @items['table']}, @items['statement']['count']['table'])
2014
+ elsif !@items['sql'].empty?
2015
+ sql = WidgetList::Utils::fill({'<!--SQL-->' => @items['sql']}, @items['statement']['count']['sql'])
2016
+ elsif !@items['view'].empty?
2017
+ sql = WidgetList::Utils::fill({'<!--VIEW-->' => @items['view']}, @items['statement']['count']['view'])
2018
+ end
2019
+
2020
+ if ! @filter.empty?
2021
+ filter = ' WHERE ' + @filter
2022
+ end
2023
+
2024
+ sql = WidgetList::Utils::fill({'<!--WHERE-->' => filter}, sql)
2025
+
2026
+ if ! sql.empty?
2027
+ if @items['showPagination']
2028
+ if WidgetList::List.get_database._select(sql, [], @items['bindVarsLegacy']) > 0
2029
+ rows = WidgetList::List.get_database.final_results['TOTAL'][0]
2030
+ else
2031
+ rows = 0
2032
+ end
2033
+ if rows > 0
2034
+ @totalRows = rows
2035
+ end
2036
+ else
2037
+ rows = 1
2038
+ end
2039
+ else
2040
+ rows = 0
2041
+ end
2042
+
2043
+ if @totalRows > 0
2044
+ @totalPages = (@totalRows.to_f / @items['rowLimit'].to_f).ceil()
2045
+ end
2046
+
2047
+ rows
2048
+ end
2049
+
2050
+ end
2051
+
2052
+ end
2053
+
2054
+