will_filter 3.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.
Files changed (110) hide show
  1. data/.loadpath +12 -0
  2. data/.project +18 -0
  3. data/CHANGELOG.rdoc +1 -0
  4. data/Gemfile +32 -0
  5. data/Gemfile.lock +73 -0
  6. data/LICENSE +18 -0
  7. data/README.rdoc +74 -0
  8. data/Rakefile +54 -0
  9. data/VERSION +1 -0
  10. data/app/controllers/application_controller.rb +27 -0
  11. data/app/controllers/will_filter/calendar_controller.rb +31 -0
  12. data/app/controllers/will_filter/exporter_controller.rb +122 -0
  13. data/app/controllers/will_filter/filter_controller.rb +107 -0
  14. data/app/helpers/application_helper.rb +26 -0
  15. data/app/models/will_filter/filter.rb +694 -0
  16. data/app/views/layouts/application.html.erb +11 -0
  17. data/app/views/will_filter/calendar/_annual.html.erb +14 -0
  18. data/app/views/will_filter/calendar/_month.html.erb +39 -0
  19. data/app/views/will_filter/calendar/_quarter.html.erb +15 -0
  20. data/app/views/will_filter/calendar/index.html.erb +52 -0
  21. data/app/views/will_filter/common/_actions_bar.html.erb +5 -0
  22. data/app/views/will_filter/common/_results_table.html.erb +129 -0
  23. data/app/views/will_filter/common/_scripts.html.erb +10 -0
  24. data/app/views/will_filter/exporter/export.html.erb +11 -0
  25. data/app/views/will_filter/exporter/index.html.erb +47 -0
  26. data/app/views/will_filter/filter/_condition.html.erb +30 -0
  27. data/app/views/will_filter/filter/_conditions.html.erb +56 -0
  28. data/app/views/will_filter/filter/_container.html.erb +31 -0
  29. data/app/views/will_filter/filter/containers/_blank.html.erb +1 -0
  30. data/app/views/will_filter/filter/containers/_boolean.html.erb +5 -0
  31. data/app/views/will_filter/filter/containers/_date.html.erb +12 -0
  32. data/app/views/will_filter/filter/containers/_date_range.html.erb +20 -0
  33. data/app/views/will_filter/filter/containers/_date_time.html.erb +12 -0
  34. data/app/views/will_filter/filter/containers/_date_time_range.html.erb +20 -0
  35. data/app/views/will_filter/filter/containers/_list.html.erb +7 -0
  36. data/app/views/will_filter/filter/containers/_numeric_range.html.erb +13 -0
  37. data/app/views/will_filter/filter/containers/_text.html.erb +7 -0
  38. data/app/views/will_filter/filter/index.html.erb +4 -0
  39. data/config/application.rb +45 -0
  40. data/config/boot.rb +6 -0
  41. data/config/database.yml +22 -0
  42. data/config/environment.rb +13 -0
  43. data/config/environments/development.rb +26 -0
  44. data/config/environments/production.rb +49 -0
  45. data/config/environments/test.rb +38 -0
  46. data/config/routes.rb +64 -0
  47. data/config/will_filter/config.yml +97 -0
  48. data/config.ru +4 -0
  49. data/db/development.sqlite3 +0 -0
  50. data/db/migrate/20090730070119_create_will_filter_tables.rb +19 -0
  51. data/db/seeds.rb +7 -0
  52. data/db/test.sqlite3 +0 -0
  53. data/doc/README_FOR_APP +2 -0
  54. data/examples/README +1 -0
  55. data/lib/application_helper.rb +45 -0
  56. data/lib/core_ext/active_record/base.rb +44 -0
  57. data/lib/core_ext/array.rb +34 -0
  58. data/lib/core_ext/object.rb +34 -0
  59. data/lib/generators/will_filter/templates/config.yml +97 -0
  60. data/lib/generators/will_filter/templates/create_will_filter_tables.rb +19 -0
  61. data/lib/generators/will_filter/will_filter_generator.rb +24 -0
  62. data/lib/tasks/.gitkeep +0 -0
  63. data/lib/tasks/will_filter_tasks.rake +32 -0
  64. data/lib/will_filter/calendar.rb +168 -0
  65. data/lib/will_filter/common_methods.rb +49 -0
  66. data/lib/will_filter/config.rb +104 -0
  67. data/lib/will_filter/containers/boolean.rb +43 -0
  68. data/lib/will_filter/containers/date.rb +51 -0
  69. data/lib/will_filter/containers/date_range.rb +56 -0
  70. data/lib/will_filter/containers/date_time.rb +50 -0
  71. data/lib/will_filter/containers/date_time_range.rb +64 -0
  72. data/lib/will_filter/containers/filter_list.rb +59 -0
  73. data/lib/will_filter/containers/list.rb +56 -0
  74. data/lib/will_filter/containers/nil.rb +45 -0
  75. data/lib/will_filter/containers/numeric.rb +52 -0
  76. data/lib/will_filter/containers/numeric_delimited.rb +50 -0
  77. data/lib/will_filter/containers/numeric_range.rb +60 -0
  78. data/lib/will_filter/containers/single_date.rb +57 -0
  79. data/lib/will_filter/containers/text.rb +45 -0
  80. data/lib/will_filter/containers/text_delimited.rb +51 -0
  81. data/lib/will_filter/engine.rb +11 -0
  82. data/lib/will_filter/filter_condition.rb +59 -0
  83. data/lib/will_filter/filter_container.rb +73 -0
  84. data/lib/will_filter/filter_exception.rb +27 -0
  85. data/lib/will_filter.rb +15 -0
  86. data/pkg/will_filter-0.1.0.gem +0 -0
  87. data/pkg/will_filter-0.1.1.gem +0 -0
  88. data/public/404.html +26 -0
  89. data/public/422.html +26 -0
  90. data/public/500.html +26 -0
  91. data/public/favicon.ico +0 -0
  92. data/public/robots.txt +5 -0
  93. data/public/will_filter/images/buttons.png +0 -0
  94. data/public/will_filter/images/calendar.png +0 -0
  95. data/public/will_filter/images/clock.png +0 -0
  96. data/public/will_filter/images/close.gif +0 -0
  97. data/public/will_filter/images/results_table_th_active.gif +0 -0
  98. data/public/will_filter/images/sort_arrow_all.gif +0 -0
  99. data/public/will_filter/images/sort_bg.gif +0 -0
  100. data/public/will_filter/images/spinner.gif +0 -0
  101. data/public/will_filter/javascripts/will_filter.js +568 -0
  102. data/public/will_filter/javascripts/will_filter_prototype_effects.js +15 -0
  103. data/public/will_filter/stylesheets/will_filter.css +168 -0
  104. data/script/rails +6 -0
  105. data/test/functional/models/will_filter/filter_test.rb +297 -0
  106. data/test/performance/browsing_test.rb +9 -0
  107. data/test/test_helper.rb +71 -0
  108. data/uninstall.rb +24 -0
  109. data/will_filter.gemspec +7 -0
  110. metadata +208 -0
@@ -0,0 +1,694 @@
1
+ #--
2
+ # Copyright (c) 2011 Michael Berkovich
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ module WillFilter
25
+ class Filter < ActiveRecord::Base
26
+ set_table_name :wf_filters
27
+ serialize :data
28
+ before_save :prepare_save
29
+ after_find :process_find
30
+
31
+ #############################################################################
32
+ # Basics
33
+ #############################################################################
34
+ def initialize(model_class)
35
+ super()
36
+ self.model_class_name = model_class.to_s
37
+ end
38
+
39
+ def dup
40
+ super.tap {|ii| ii.conditions = self.conditions.dup}
41
+ end
42
+
43
+ def prepare_save
44
+ self.data = serialize_to_params
45
+ self.type = self.class.name
46
+ end
47
+
48
+ def process_find
49
+ @errors = {}
50
+ deserialize_from_params(self.data)
51
+ end
52
+
53
+ #############################################################################
54
+ # Defaults
55
+ #############################################################################
56
+ def show_export_options?
57
+ WillFilter::Config.exporting_enabled?
58
+ end
59
+
60
+ def show_save_options?
61
+ WillFilter::Config.saving_enabled?
62
+ end
63
+
64
+ def match
65
+ @match ||= :all
66
+ end
67
+
68
+ def key
69
+ @key ||= ''
70
+ end
71
+
72
+ def errors
73
+ @errors ||= {}
74
+ end
75
+
76
+ def format
77
+ @format ||= :html
78
+ end
79
+
80
+ def fields
81
+ @fields ||= []
82
+ end
83
+
84
+ #############################################################################
85
+ # a list of indexed fields where at least one of them has to be in a query
86
+ # otherwise the filter may hang the database
87
+ #############################################################################
88
+ def required_condition_keys
89
+ []
90
+ end
91
+
92
+ def model_class
93
+ return nil unless model_class_name
94
+ @model_class ||= model_class_name.constantize
95
+ end
96
+
97
+ def table_name
98
+ model_class.table_name
99
+ end
100
+
101
+ def key=(new_key)
102
+ @key = new_key
103
+ end
104
+
105
+ def match=(new_match)
106
+ @match = new_match
107
+ end
108
+
109
+ #############################################################################
110
+ # Inner Joins come in a form of
111
+ # [[joining_model_name, column_name], [joining_model_name, column_name]]
112
+ #############################################################################
113
+ def inner_joins
114
+ []
115
+ end
116
+
117
+ def model_columns
118
+ model_class.columns
119
+ end
120
+
121
+ def model_column_keys
122
+ model_columns.collect{|col| col.name.to_sym}
123
+ end
124
+
125
+ def contains_column?(key)
126
+ model_column_keys.index(key) != nil
127
+ end
128
+
129
+ def definition
130
+ @definition ||= begin
131
+ defs = {}
132
+ model_columns.each do |col|
133
+ defs[col.name.to_sym] = default_condition_definition_for(col.name, col.sql_type)
134
+ end
135
+
136
+ inner_joins.each do |inner_join|
137
+ join_class = inner_join.first.to_s.camelcase.constantize
138
+ join_class.columns.each do |col|
139
+ defs[:"#{join_class.to_s.underscore}.#{col.name.to_sym}"] = default_condition_definition_for(col.name, col.sql_type)
140
+ end
141
+ end
142
+
143
+ defs
144
+ end
145
+ end
146
+
147
+ def container_by_sql_type(type)
148
+ raise WillFilter::FilterException.new("Unsupported data type #{type}") unless WillFilter::Config.data_types[type]
149
+ WillFilter::Config.data_types[type]
150
+ end
151
+
152
+ def default_condition_definition_for(name, sql_data_type)
153
+ type = sql_data_type.split(" ").first.split("(").first.downcase
154
+ containers = container_by_sql_type(type)
155
+ operators = {}
156
+ containers.each do |c|
157
+ raise WillFilter::FilterException.new("Unsupported container implementation for #{c}") unless WillFilter::Config.containers[c]
158
+ container_klass = WillFilter::Config.containers[c].constantize
159
+ container_klass.operators.each do |o|
160
+ operators[o] = c
161
+ end
162
+ end
163
+
164
+ if name == "id"
165
+ operators[:is_filtered_by] = :filter_list
166
+ elsif "_id" == name[-3..-1]
167
+ begin
168
+ name[0..-4].camelcase.constantize
169
+ operators[:is_filtered_by] = :filter_list
170
+ rescue
171
+ end
172
+ end
173
+
174
+ operators
175
+ end
176
+
177
+ def sorted_operators(opers)
178
+ (WillFilter::Config.operator_order & opers.keys.collect{|o| o.to_s})
179
+ end
180
+
181
+ def first_sorted_operator(opers)
182
+ sorted_operators(opers).first.to_sym
183
+ end
184
+
185
+ def default_order
186
+ 'id'
187
+ end
188
+
189
+ def order
190
+ @order ||= default_order
191
+ end
192
+
193
+ def default_order_type
194
+ 'desc'
195
+ end
196
+
197
+ def order_type
198
+ @order_type ||= default_order_type
199
+ end
200
+
201
+ def order_clause
202
+ "#{order} #{order_type}"
203
+ end
204
+
205
+ def column_sorted?(key)
206
+ key.to_s == order
207
+ end
208
+
209
+ def default_per_page
210
+ 30
211
+ end
212
+
213
+ def per_page
214
+ @per_page ||= default_per_page
215
+ end
216
+
217
+ def page
218
+ @page ||= 1
219
+ end
220
+
221
+ def default_per_page_options
222
+ [10, 20, 30, 40, 50, 100]
223
+ end
224
+
225
+ def per_page_options
226
+ @per_page_options ||= default_per_page_options.collect{ |n| [n.to_s, n.to_s] }
227
+ end
228
+
229
+ def match_options
230
+ [["all", "all"], ["any", "any"]]
231
+ end
232
+
233
+ def order_type_options
234
+ [["desc", "desc"], ["asc", "asc"]]
235
+ end
236
+
237
+ #############################################################################
238
+ # Can be overloaded for custom titles
239
+ #############################################################################
240
+ def condition_title_for(key)
241
+ title = key.to_s.gsub(".", ": ").gsub("_", " ")
242
+ title.split(" ").collect{|part| part.capitalize}.join(" ")
243
+ end
244
+
245
+ def condition_options
246
+ @condition_options ||= begin
247
+ opts = []
248
+ definition.keys.each do |cond|
249
+ opts << [condition_title_for(cond), cond.to_s]
250
+ end
251
+ opts.sort_by{ |i| i[0] }
252
+ end
253
+ end
254
+
255
+ def operator_options_for(condition_key)
256
+ condition_key = condition_key.to_sym if condition_key.is_a?(String)
257
+
258
+ opers = definition[condition_key]
259
+ raise WillFilter::FilterException.new("Invalid condition #{condition_key} for filter #{self.class.name}") unless opers
260
+ sorted_operators(opers).collect{|o| [o.to_s.gsub('_', ' '), o]}
261
+ end
262
+
263
+ # called by the list container, should be overloaded in a subclass
264
+ def value_options_for(condition_key)
265
+ []
266
+ end
267
+
268
+ def container_for(condition_key, operator_key)
269
+ condition_key = condition_key.to_sym if condition_key.is_a?(String)
270
+
271
+ opers = definition[condition_key]
272
+ raise WillFilter::FilterException.new("Invalid condition #{condition_key} for filter #{self.class.name}") unless opers
273
+ oper = opers[operator_key]
274
+
275
+ # if invalid operator_key was passed, use first operator
276
+ oper = opers[first_sorted_operator(opers)] unless oper
277
+ oper
278
+ end
279
+
280
+ def add_condition(condition_key, operator_key, values = [])
281
+ add_condition_at(size, condition_key, operator_key, values)
282
+ end
283
+
284
+ def valid_operator?(condition_key, operator_key)
285
+ condition_key = condition_key.to_sym if condition_key.is_a?(String)
286
+ opers = definition[condition_key]
287
+ return false unless opers
288
+ opers[operator_key]!=nil
289
+ end
290
+
291
+ def add_condition_at(index, condition_key, operator_key, values = [])
292
+ values = [values] unless values.instance_of?(Array)
293
+ values = values.collect{|v| v.to_s}
294
+
295
+ condition_key = condition_key.to_sym if condition_key.is_a?(String)
296
+
297
+ unless valid_operator?(condition_key, operator_key)
298
+ opers = definition[condition_key]
299
+ operator_key = first_sorted_operator(opers)
300
+ end
301
+
302
+ condition = WillFilter::FilterCondition.new(self, condition_key, operator_key, container_for(condition_key, operator_key), values)
303
+ @conditions.insert(index, condition)
304
+ end
305
+
306
+ #############################################################################
307
+ # options always go in [NAME, KEY] format
308
+ #############################################################################
309
+ def default_condition_key
310
+ condition_options.first.last
311
+ end
312
+
313
+ #############################################################################
314
+ # options always go in [NAME, KEY] format
315
+ #############################################################################
316
+ def default_operator_key(condition_key)
317
+ operator_options_for(condition_key).first.last
318
+ end
319
+
320
+ def conditions=(new_conditions)
321
+ @conditions = new_conditions
322
+ end
323
+
324
+ def conditions
325
+ @conditions ||= []
326
+ end
327
+
328
+ def condition_at(index)
329
+ conditions[index]
330
+ end
331
+
332
+ def condition_by_key(key)
333
+ conditions.each do |c|
334
+ return c if c.key==key
335
+ end
336
+ nil
337
+ end
338
+
339
+ def size
340
+ conditions.size
341
+ end
342
+
343
+ def add_default_condition_at(index)
344
+ add_condition_at(index, default_condition_key, default_operator_key(default_condition_key))
345
+ end
346
+
347
+ def remove_condition_at(index)
348
+ conditions.delete_at(index)
349
+ end
350
+
351
+ def remove_all
352
+ @conditions = []
353
+ end
354
+
355
+ #############################################################################
356
+ # Serialization
357
+ #############################################################################
358
+ def serialize_to_params(merge_params = {})
359
+ params = {}
360
+ params[:wf_type] = self.class.name
361
+ params[:wf_match] = match
362
+ params[:wf_model] = model_class_name
363
+ params[:wf_order] = order
364
+ params[:wf_order_type] = order_type
365
+ params[:wf_per_page] = per_page
366
+ params[:wf_export_fields] = fields.join(',')
367
+ params[:wf_export_format] = format
368
+
369
+ 0.upto(size - 1) do |index|
370
+ condition = condition_at(index)
371
+ condition.serialize_to_params(params, index)
372
+ end
373
+
374
+ params.merge(merge_params)
375
+ end
376
+
377
+ #############################################################################
378
+ # allows to create a filter from params only
379
+ #############################################################################
380
+ def self.deserialize_from_params(params)
381
+ params = HashWithIndifferentAccess.new(params) unless params.is_a?(HashWithIndifferentAccess)
382
+ params[:wf_type] = self.name unless params[:wf_type]
383
+ params[:wf_type].constantize.new(params[:wf_model]).deserialize_from_params(params)
384
+ end
385
+
386
+ def deserialize_from_params(params)
387
+ params = HashWithIndifferentAccess.new(params) unless params.is_a?(HashWithIndifferentAccess)
388
+ @conditions = []
389
+ @match = params[:wf_match] || :all
390
+ @key = params[:wf_key] || self.id.to_s
391
+ self.model_class_name = params[:wf_model] if params[:wf_model]
392
+
393
+ @per_page = params[:wf_per_page] || default_per_page
394
+ @page = params[:page] || 1
395
+ @order_type = params[:wf_order_type] || default_order_type
396
+ @order = params[:wf_order] || default_order
397
+
398
+ self.id = params[:wf_id].to_i unless params[:wf_id].blank?
399
+ self.name = params[:wf_name] unless params[:wf_name].blank?
400
+
401
+ @fields = []
402
+ unless params[:wf_export_fields].blank?
403
+ params[:wf_export_fields].split(",").each do |fld|
404
+ @fields << fld.to_sym
405
+ end
406
+ end
407
+
408
+ if params[:wf_export_format].blank?
409
+ @format = :html
410
+ else
411
+ @format = params[:wf_export_format].to_sym
412
+ end
413
+
414
+ i = 0
415
+ while params["wf_c#{i}"] do
416
+ conditon_key = params["wf_c#{i}"]
417
+ operator_key = params["wf_o#{i}"]
418
+ values = []
419
+ j = 0
420
+ while params["wf_v#{i}_#{j}"] do
421
+ values << params["wf_v#{i}_#{j}"]
422
+ j += 1
423
+ end
424
+ i += 1
425
+ add_condition(conditon_key, operator_key.to_sym, values)
426
+ end
427
+
428
+ if params[:wf_submitted] == 'true'
429
+ validate!
430
+ end
431
+
432
+ return self
433
+ end
434
+
435
+ #############################################################################
436
+ # Validations
437
+ #############################################################################
438
+ def errors?
439
+ (@errors and @errors.size > 0)
440
+ end
441
+
442
+ def empty?
443
+ size == 0
444
+ end
445
+
446
+ def has_condition?(key)
447
+ condition_by_key(key) != nil
448
+ end
449
+
450
+ def valid_format?
451
+ WillFilter::Config.default_export_formats.include?(format.to_s)
452
+ end
453
+
454
+ def required_conditions_met?
455
+ return true if required_condition_keys.blank?
456
+ sconditions = conditions.collect{|c| c.key.to_s}
457
+ rconditions = required_condition_keys.collect{|c| c.to_s}
458
+ not (sconditions & rconditions).empty?
459
+ end
460
+
461
+ def validate!
462
+ @errors = {}
463
+ 0.upto(size - 1) do |index|
464
+ condition = condition_at(index)
465
+ err = condition.validate
466
+ @errors[index] = err if err
467
+ end
468
+
469
+ unless required_conditions_met?
470
+ @errors[:filter] = "Filter must contain at least one of the following conditions: #{required_condition_keys.join(", ")}"
471
+ end
472
+
473
+ errors?
474
+ end
475
+
476
+ #############################################################################
477
+ # SQL Conditions
478
+ #############################################################################
479
+ def sql_conditions
480
+ @sql_conditions ||= begin
481
+
482
+ if errors?
483
+ all_sql_conditions = [" 1 = 2 "]
484
+ else
485
+ all_sql_conditions = [""]
486
+ 0.upto(size - 1) do |index|
487
+ condition = condition_at(index)
488
+ sql_condition = condition.container.sql_condition
489
+
490
+ unless sql_condition
491
+ raise WillFilter::FilterException.new("Unsupported operator #{condition.operator_key} for container #{condition.container.class.name}")
492
+ end
493
+
494
+ if all_sql_conditions[0].size > 0
495
+ all_sql_conditions[0] << ( match.to_sym == :all ? " AND " : " OR ")
496
+ end
497
+
498
+ all_sql_conditions[0] << sql_condition[0]
499
+ sql_condition[1..-1].each do |c|
500
+ all_sql_conditions << c
501
+ end
502
+ end
503
+ end
504
+
505
+ all_sql_conditions
506
+ end
507
+ end
508
+
509
+ def debug_conditions(conds)
510
+ all_conditions = []
511
+ conds.each_with_index do |c, i|
512
+ cond = ""
513
+ if i == 0
514
+ cond << "\"<b>#{c}</b>\""
515
+ else
516
+ cond << "<br>&nbsp;&nbsp;&nbsp;<b>#{i})</b>&nbsp;"
517
+ if c.is_a?(Array)
518
+ cond << "["
519
+ cond << (c.collect{|v| "\"#{v.strip}\""}.join(", "))
520
+ cond << "]"
521
+ elsif c.is_a?(Date)
522
+ cond << "\"#{c.strftime("%Y-%m-%d")}\""
523
+ elsif c.is_a?(Time)
524
+ cond << "\"#{c.strftime("%Y-%m-%d %H:%M:%S")}\""
525
+ elsif c.is_a?(Integer)
526
+ cond << c.to_s
527
+ else
528
+ cond << "\"#{c}\""
529
+ end
530
+ end
531
+
532
+ all_conditions << cond
533
+ end
534
+ all_conditions
535
+ end
536
+
537
+ def debug_sql_conditions
538
+ debug_conditions(sql_conditions)
539
+ end
540
+
541
+ #############################################################################
542
+ # Saved Filters
543
+ #############################################################################
544
+ def saved_filters(include_default = true)
545
+ @saved_filters ||= begin
546
+ filters = []
547
+
548
+ if include_default
549
+ filters = default_filters
550
+ if (filters.size > 0)
551
+ filters.insert(0, ["-- Select Default Filter --", "-1"])
552
+ end
553
+ end
554
+
555
+ if include_default
556
+ conditions = ["type = ? and model_class_name = ?", self.class.name, self.model_class_name]
557
+ else
558
+ conditions = ["model_class_name = ?", self.model_class_name]
559
+ end
560
+
561
+ if WillFilter::Config.user_filters_enabled?
562
+ conditions[0] << " and user_id = ? "
563
+ if WillFilter::Config.current_user and WillFilter::Config.current_user.id
564
+ conditions << WillFilter::Config.current_user.id
565
+ else
566
+ conditions << "0"
567
+ end
568
+ end
569
+
570
+ user_filters = WillFilter::Filter.find(:all, :conditions => conditions)
571
+
572
+ if user_filters.size > 0
573
+ filters << ["-- Select Saved Filter --", "-2"] if include_default
574
+
575
+ user_filters.each do |filter|
576
+ filters << [filter.name, filter.id.to_s]
577
+ end
578
+ end
579
+
580
+ filters
581
+ end
582
+ end
583
+
584
+ #############################################################################
585
+ # overload this method if you don't want to allow empty filters
586
+ #############################################################################
587
+ def default_filter_if_empty
588
+ nil
589
+ end
590
+
591
+ def handle_empty_filter!
592
+ return unless empty?
593
+ return if default_filter_if_empty.nil?
594
+ load_filter!(default_filter_if_empty)
595
+ end
596
+
597
+ def default_filters
598
+ []
599
+ end
600
+
601
+ def default_filter_conditions(key)
602
+ []
603
+ end
604
+
605
+ def load_default_filter(key)
606
+ default_conditions = default_filter_conditions(key)
607
+ return if default_conditions.nil? or default_conditions.empty?
608
+
609
+ unless default_conditions.first.is_a?(Array)
610
+ add_condition(*default_conditions)
611
+ return
612
+ end
613
+
614
+ default_conditions.each do |default_condition|
615
+ add_condition(*default_condition)
616
+ end
617
+ end
618
+
619
+ def reset!
620
+ remove_all
621
+ @sql_conditions = nil
622
+ @results = nil
623
+ end
624
+
625
+ def load_filter!(key_or_id)
626
+ reset!
627
+ @key = key_or_id.to_s
628
+
629
+ load_default_filter(key)
630
+ return self unless empty?
631
+
632
+ filter = WillFilter::Filter.find_by_id(key_or_id.to_i)
633
+ raise WillFilter::FilterException.new("Invalid filter key #{key_or_id.to_s}") if filter.nil?
634
+ filter
635
+ end
636
+
637
+ #############################################################################
638
+ # Export Filter Data
639
+ #############################################################################
640
+ def export_formats
641
+ formats = []
642
+ formats << ["-- Generic Formats --", -1]
643
+ WillFilter::Config.default_export_formats.each do |frmt|
644
+ formats << [frmt, frmt]
645
+ end
646
+ if custom_formats.size > 0
647
+ formats << ["-- Custom Formats --", -2]
648
+ custom_formats.each do |frmt|
649
+ formats << frmt
650
+ end
651
+ end
652
+ formats
653
+ end
654
+
655
+ def custom_format?
656
+ custom_formats.each do |frmt|
657
+ return true if frmt[1].to_sym == format
658
+ end
659
+ false
660
+ end
661
+
662
+ def custom_formats
663
+ []
664
+ end
665
+
666
+ def process_custom_format
667
+ ""
668
+ end
669
+
670
+ def joins
671
+ return nil if inner_joins.empty?
672
+ inner_joins.collect do |inner_join|
673
+ join_table_name = inner_join.first.to_s.camelcase.constantize.table_name
674
+ join_on_field = inner_join.last.to_s
675
+ "INNER JOIN #{join_table_name} ON #{join_table_name}.id = #{table_name}.#{join_on_field}"
676
+ end
677
+ end
678
+
679
+ def results
680
+ @results ||= begin
681
+ handle_empty_filter!
682
+
683
+ recs = model_class.paginate(:order => order_clause, :page => page, :per_page => per_page, :conditions => sql_conditions, :joins => joins)
684
+ recs.wf_filter = self
685
+ recs
686
+ end
687
+ end
688
+
689
+ # sums up the column for the given conditions
690
+ def sum(column_name)
691
+ model_class.sum(column_name, :conditions => sql_conditions)
692
+ end
693
+ end
694
+ end
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>will_filter</title>
5
+ </head>
6
+ <body>
7
+
8
+ <%= yield %>
9
+
10
+ </body>
11
+ </html>
@@ -0,0 +1,14 @@
1
+ <table class="wf_calendar_table" cellpadding="0" cellspacing="0">
2
+ <tr>
3
+ <% 0.upto(11) do |m| %>
4
+ <% if m % 4 == 0 %>
5
+ </tr><tr>
6
+ <% end %>
7
+ <td valign="top">
8
+ <% next_cal = calendar.move(m.months) %>
9
+ <div class="wf_calendar_title"><%=next_cal.title %></div>
10
+ <%= render :partial => "month", :locals => {:calendar => next_cal} %>
11
+ </td>
12
+ <% end %>
13
+ </tr>
14
+ </table>