will_filter 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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>